super(..) calling getattr (was: RE: Question about accessing class-attributes.)

Michele Simionato mis6 at pitt.edu
Thu May 1 13:29:13 EDT 2003


"Bjorn Pettersen" <BPettersen at NAREX.com> wrote in message news:<mailman.1051766882.28049.python-list at python.org>...
> <snip>
> So really, we don't need to think about the class of super(..) in this
> instance at all, we just need to ask the individual classes on the mro
> if they can handle attribute 'foo' through their   getattr   if they
> can't from their regular lookup. Modified Super (index can throw, but I
> think it illustrates what's going on better :-)
> 
>   class Super(object):
>      def   init  (self, type, obj=None):
>         self.  type   = type
>         self.  obj   = obj
>   
>      def   get  (self, obj, type=None):
>         if self.  obj   is None and obj is not None:
>            return Super(self.  type  , obj)
>         else:
>            return self
>            
>      def   getattr  (self, attr):
>         if isinstance(self.  obj  , self.  type  ):
>            mro = list(self.  obj  .  class  .  mro  )
>         else:
>            mro = list(self.  obj  .  mro  )
>   
>         mro = mro[mro.index(self.  type  ) + 1:]
>   
>         for cls in mro:
>            if attr in cls.  dict  :
>               x = cls.  dict  [attr]
>               if hasattr(x, '  get  '):
>                  return x.  get  (self.  obj  )
>               else:
>                  return x
>               
>            if hasattr(cls, '  getattr  '):
>               try:
>                  return cls.  getattr  (self.  obj  , attr)
>               except AttributeError:
>                  pass
>               
>         raise AttributeError, attr
> 
> I've tested it both on the classic diamond, and on:
> 
>    class BB(object):
>       def   getattr  (self, attr):
>          return lambda:attr
>    
>    class B(BB):
>       def foo(self): print 'B.foo'
>       
>       def   getattr  (self, attr):
>          if attr == 'bar':
>             print 'B.  getattr  ("bar")'
>             return lambda:42
>          else:
>             raise AttributeError(attr)
>       
>    class D(B):
>       def foo(self):
>          Super(D, self).foo()
>          self.supercls.foo()
>          print 'D.foo'
>          
>       def bar(self):
>          v = Super(D, self).bar()
>          print v
>          
>       def baz(self):
>          v = Super(D, self).baz()
>          print v
>          
>    D.supercls = Super(D)
>          
>    d = D()
>    d.foo()
>    d.bar()
>    d.baz()
> 
> both with and without BB as the top of the hierarchy. It seems to behave
> like
> 
>   B.foo(self)
>   B.bar(self)
>   B.baz(self)
> 
> which I would argue is the correct behavior... (and for Super(D,
> self).baz(), I'd argue it's much simpler than what you'd have to write
> today <wink>).
> 
> Comments?
> 
> -- bjorn

I haven't read it carefully, however pay attention that supercls must be
a private attribute, otherwise you will have bad surprises when you will
subclass D, say with E and you will write E.supercls=super(E): in this case
self will be an instance of E and self.supercls invoked inside D
will look at the superclass of E, not of D, which is not what you want.

 
                                Michele




More information about the Python-list mailing list