multiple inheritance and __getattr__

David C. Ullrich dullrich at sprynet.com
Tue Jul 29 11:40:39 EDT 2008


In article <488e2e70$0$29472$426a74cc at news.free.fr>,
 Bruno Desthuilliers <bdesth.quelquechose at free.quelquepart.fr> wrote:

> Enrico a écrit :
> > Hi there,
> > I have the following situation (I tryed to minimize the code to concentrate
> > on the issue):
> > 
> >>>> class A(object):
> >  def __getattr__(self, name):
> >   print 'A.__getattr__'
> >   if name == 'a': return 1
> >   raise AttributeError('%s not found in A' % name)
> > 
> >>>> class B(object):
> >  def __getattr__(self, name):
> >   print 'B.__getattr__'
> >   if name == 'b': return 1
> >   raise AttributeError('%s not found in B' % name)
> > 
> > Both classes have a __getattr__ method.
> > Now I want to have a class that inherits from both so I write:
> > 
> >>>> class C(B,A):
> >  pass
> > 
> > The problem arise when I try something like this:
> >>>> c=C()
> >>>> c.a
> > A.__getattr__
> > 1
> >>>> c.b
> > A.__getattr__
> > 
> > Traceback (most recent call last):
> >   File "<pyshell#47>", line 1, in <module>
> >     c.b
> >   File "<pyshell#42>", line 5, in __getattr__
> >     raise AttributeError('%s not found in A' % name)
> > AttributeError: b not found in A
> 
> That's what I would have expected.
> 
> > I was expecting, after a fail in A.__getattr__,  a call to the __getattr__
> > method of B but it seems that after A.__getattr__ fails the exception stops
> > the flow.
> 
> Indeed. You explicitely raise, so the lookup stops here.

??? Surely the reason the lookup stops there is that a __getattr__
was _found_. In the code below the lookup is not continuing,
there's a _second_ lookup started by the request for super.__getattr__.

> You'd need to 
> explicitely call on superclass instead to have B.__getattr__ called, ie:
> 
> class A(object):
>      def __getattr__(self, name):
>          if name == 'a':
>              return 1
>          return super(A, self).__getattr__(name)
> 
> class B(object):
>      def __getattr__(self, name):
>          if name == 'b':
>              return 2
>          return super(B, self).__getattr__(name)
> 
> class C(A, B):
>      pass
>

-- 
David C. Ullrich



More information about the Python-list mailing list