[Python-Dev] Computed-attributes
Gordon McMillan
gmcm@hypernet.com
Thu, 20 Jul 2000 13:03:13 -0400
Paul Prescod wrote:
> Gordon McMillan wrote:
> >
> > What happens here (and when):
> > class A:
> > y = None
> > class B(A):
> > def __XXX_y__(self):
> > ...
>
> I would say that the latter would just take precedence over the
> former as if you had typed:
>
> class B(A):
> __XXX_y__=ComputedAttribute( foo, bar, baz )
OK. I gather that the ComputedAttribute is actually named
after the attribute. So in this situation, "y" is found in
B.__dict__, and is a ComputedAttribute which hides A's
(normal) attribute. Then:
class A:
def __init__(self):
self.y = <something>
class B(A):
def __set_y__(self, value):
...
def __init__(self):
A.__init__(self)
means that the hook in B will be invoked when A.__init__
runs. I wonder what "gotchas" lie in wait ;-).
> > Hmmm. Current Python: search for y fails, try __getattr__.
> > Proposed: search for y fails, try the __get_y__, then
> > __getattr__. We've still done the same work before trying the
> > hook, so how is performance affected?
I hadn't realized when I wrote that that the ComputedAttribute
would have the attribute's name. That does make getattr faster.
But:
> Actually, I was justifying Python's current behavior as much as I
> was the current behavior. A truly general __getattr__ would
> access all attribute tests, not just non-existent attributes and
> thus be symmetric with setattr. But that would also be slow as
> hell.
I use __getattr__ most often to do lazy evaluation. So:
def __getattr__(self, nm):
if nm == 'doohickies':
rslt = self.doohickies = <long calc>
return rslt
Yes, you can do this either way, but I rather like the fact that
it's a last resort hook.
> > class A:
> > def __get_y__(self):
> > ...
> > class B(A):
> > def __set_y__(self, value):
> > ....
>
> My first instinct is just to disallow this and figure it out
> after we have some more usage information/implementation
> resources. We could just say that all methods must be defined in
> the same class and if not. In other words, the methods "shadow
> each other" as a group.
>
> This is no more messy than inherited __getattr__ s.
Not at all. The complexity of doing __getattr__ and __setattr__
hooks is all in the class you implement them in. There's no
*new* complexity in going to base class implementations -
you just chain as usual. The only surprise might be that if the
hapless subclasser doesn't realize that some base class has
a __setattr__ hook set.
I'm not against this proposal. But I think there are *no* "safe"
ways of doing attr hacks; and simply getting to "safer" may be
a whole lot of work.
[I also note that there are quite a few Python developers who
want their users to say "x = obj.getx()", but want Python to
create the accessor method "getx(self)" (if they haven't written
one) and outlaw "x = obj.x". I have no sympathy for them, but
they exist.]
- Gordon