properties and formatting with self.__dict__
Andrew Bennetts
andrew-pythonlist at puzzling.org
Sat Feb 22 08:43:58 EST 2003
On Sat, Feb 22, 2003 at 08:27:39AM +0000, Alex Martelli wrote:
> Andrew Bennetts wrote:
>
> > I na?vely assumed that descriptors worked equally well for instances
> > as for classes, which turns out not to be true. If it was, it would
> > indeed be fairly easy...
>
> Hmmm, wouldn't such a change cause breakage elsewhere?
Almost certainly, yeah. It'd make this particular insane use-case easier,
though ;)
> > So I was wrong -- you'd have to define custom metaclass, or something
> > along
> > those lines. You could probably avoid a metaclass with something like:
> >
> > class C:
> > def __init__(self, ...):
> > instanceproperty(self, 'fullname', self.getfullname)
> >
> > where instanceproperty was a function that inserted some sort of evil
> > descriptor into C.fullname if there wasn't already one... but it'd be
> > worse than simply defining __getattribute__ or __getattr__.
>
> It wouldn't be a per-instance descriptor if it changed the class, though.
> It's either a way for instances to trip on each other (when you define
> the second istance ITS self.getfullname bound method gets called
> even for the already-existing first instance) or just a weird way to
> insert a normal-ish descriptor in a class, no?
You could probably make it check for the following cases:
- there is already an evil fullname property installed, so just register
with it
- there is already an ordinary attribute 'fullname', so put an evil
descriptor attribute there that knows to mimic the ordinary attribute
for some instances
It's such a nasty idea that I'm not even going to try coding it...
> > Hmm... maybe you could abuse metaclasses to return a freshly minted class
> > object instead of a mere instance, so that descriptors would work....
> >
> > [experiments]
> >
[..code snipped..]
> >
> > Which isn't too far removed from:
> >
> > class C:
> > def __init__(self):
> > self.fullname = property(self.getfullname)
> >
> > def getfullname(self):
> > return 'Andrew Bennetts'
> >
> > Well, you'd have to stand a few metres back from the monitor and squint,
> > but
> > then it kinda sorta looks similar <wink>. Perhaps with a bit more
> > cleverness you could simplify my hack more.
>
> It may help to coat the monitor with semi-opaque substances too;-).
Facing the other way probably helps even more :)
> As for simplification, one clever hack may be to notice that, since
> instanceIsClass only provides __new__ and C overrides it anyway,
> instanceIsClass is playing no role:
Hmm! You're right...
> class C(object):
>
> def __new__(self):
> self.fullname = property(self.getfullname)
> return object.__new__(self)
>
> def getfullname(self):
> return 'Andrew Bennetts'
>
> x=C()
>
> print x.fullname
>
>
> But of course the "self" in C.__new__ is C itself, so what we're
> doing is setting a property on the *class* C, not on any one of its
> instances. We're setting it a bit late, and redundantly setting it
> again to a new instance of property with the same __get__
> (which calls unbound method C.getfullname), but it is in no
> sense a per-instance property...
Yeah. That of course effectively boils down to just doing:
class C(object):
def getfullname(self):
return 'Andrew Bennetts'
fullname = property(getFullname)
which is pretty obviously not what we're after.
Instead, you'd have to resort to something like this:
class instanceIsClass(object):
def __new__(cls, *args, **kwargs):
class Instance(cls):
def __new__(cls):
return object.__new__(cls)
return Instance
class C(instanceIsClass):
def __new__(self, fn):
o = instanceIsClass.__new__(self)
o.fn = fn
o.fullname = property(o.getfullname)
print 'C.__new__ returning', repr(o)
return o()
def getfullname(self):
return 'Full name: ' + self.fn
c1 = C('Bozo the clown')
c2 = C('Guido the PSU operative')
print c1, ',', c2
print c1.fullname, ',', c2.fullname
Again, I think this could probably be simplified by somehow combining the
two __new__s...
It's starting to look like it might not be worth the pain ;)
> > Thanks for helping me realise that I'd assumed wrongly :)
>
> You're welcome -- this stuff IS subtle, so I really hoped I was the
> one that had misunderstood something (would hardly be the first
> time;-). Perhaps more interestingly, can you think of a way to
> change object that WOULD let per-class properties work without
^^^^^^^^^
I presume you mean per-instance?
> breaking something else? I can't. A custom metaclass that does
> allow per-instance properties could not be used universally, it
> seems to me. But you may have thought more deeply about it...
No, I haven't thought about it deeply at all, as my mistakes so far
should've shown :)
I can't think of any reason off the top of my head why instance descriptors
would break anything, but I strongly suspect they would. I also can't think
of a compelling use-case for per-instance descriptors off the top of my
head... between class descriptors, and __getattr__ and __getattribute__,
there's probably not much need to complicate things further.
-Andrew.
More information about the Python-list
mailing list