New PEP: Attribute Access Handlers

Gordon McMillan gmcm at hypernet.com
Sat Jul 22 11:35:43 EDT 2000


Bjorn Pettersen wrote: 

>Paul Prescod wrote:

>> Actually, I'm not sure if my proposal would help here. Appending to a
>> cStringIO is not an assignment operation...
>
>The only requirement was that the attribute access (myObject.property)
>stay the same, only instead of returning a string it would compute
>.value() on the cStringIO object. I.e., original:
>
>  class MyObject:
>    def __init__(self,s):
>      self.s = s
>
>new version:
>
>  class MyObject:
>    def __init__(self,s):
>      self._s = cStringIO.StringIO(s)
>    def __getattr__(self, a):
>      if a == 's':
>        return self.__dict__['_s'].value()
>      else:
>        return self.__dict__[a]

Umm, that should be:
  def __getattr__(self, a):
    if a == 's':
       return self._s.value()
    raise AttributeError, a

(__getattr__ is last resort - not called if the attribute is found.)


>> > Perhaps you should add a few words about why you chose __attr_XXX__
>> > instead of __set/get/del_XXX__?
>> 
>> That was actually the first proposal. But inheritance could get
>> confusing if you inherited set without get or get without set etc.
>
>Hmmm... I'm not quite sure I understand... 

Of course you don't! Because Paul forgot to tell you that the first 
proposal said that defining one or more of __set/get/del_XXX__ 
automatically defines all 3, with default behavior of "you can't do that". 
So a base class defining __get_X__ and a derived class defining __set_X__ 
will have the wrong semantics 50% of the time whichever way you choose to 
handle it.

>With __set/get/del_XXX__
>defined in a superclass you would automatically inherit all of them and
>could choose to only override one of them, e.g. if you wanted to perform
>further checks on a set but the get was the same.  With __attr_XXX__ you
>would have to explicitly call the superclass' __attr_XXX__ method if you
>didn't define all of set/get/del(?)  I have a feeling I'm missing
>something...

The current implementation has one generalized "access handler" for each 
type of access (get/set/del). For set/del, the handler is always called, 
meaning you have to write the class (and derived classes) with this in 
mind.

Both versions of this proposal work by installing an "access handler" for 
an attribute. In the first, the fact that there was one "access handler" 
was completely implicit - it looked like there were 3. So it would be 
ambiguous whether the author of an override knew what they were doing 
(overriding the "access handler"), or being naive (attempting to override 
just one method of the "access handler").

In the current version, it's pretty obvious that you are overriding the 
one-and-only "access handler". But since the handler has the name of the 
attribute, chaining to a base class implementation means we need the 
handler also available under a different name.

-Gordon



More information about the Python-list mailing list