multiple inheritance and __getattr__
David C. Ullrich
dullrich at sprynet.com
Mon Jul 28 11:58:22 EDT 2008
In article <488ddc51$0$41654$4fafbaef at reader4.news.tin.it>,
"Enrico" <4564 at 755189.45> wrote:
> 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
>
> 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. So, if I did understand well, B.__getattr__ will be never called
> "automatically". I don't know if this has a reason, if it is a design choice
> or what else, any explanation is welcome.
Well, it's simply the way it works. When you say C(A, B) then A is
searched first for a given attribute and if A has no such attribute
then B is searched. If you really want to do something like this
then yes, you have to do something as below.
I suspect that the people who feel expert enough to talk about what
you should and shouldn't want are going to say that you shouldn't
want something like this - with things set up the way you have them
you really can't tell what's going to happen with c.__getattr__
unless you look at all the code in all the subclasses.
> Since A and B are not written by me I can only work on C. The solution that
> comes to my mind is to define a __getattr__ also in C and write something
> like:
>
> >>> class C(A,B):
> def __getattr__(self, name):
> try:
> return A.__getattr__(self, name)
> except AttributeError:
> return B.__getattr__(self, name)
>
> >>> c=C()
> >>> c.a
> A.__getattr__
> 1
> >>> c.b
> A.__getattr__
> B.__getattr__
> 1
>
> A better solution is welcome.
> Many thanks, Enrico
--
David C. Ullrich
More information about the Python-list
mailing list