Default attribute in base class precludes delegation
hans at zephyrfalcon.org
Fri Dec 19 06:02:34 CET 2003
Gabriel Genellina wrote:
> In the following code sample, I have:
> - a Worker class, which could have a lot of methods and attributes. In
> particular, it has a 'bar' attribute. This class can be modified as needed.
> - a Base class (old-style) which defines a default class attribute 'bar'
> too. I can't modify the source code of this class. Note that Workes does
> not inherit from Base.
> - a Derived class which must inherit from Base and is a wrapper around
> Worker: it contains a Worker instance and delegates almost anything to
> it. This class can be modified as needed too.
> For most attributes, as they are not found in the Derived instance's
> dict, __getattr__ is called and the attribute is retrieved from the
> Worker instance.
> But for the 'bar' attribute, it is found in the Base class and just the
> default value is returned. __getattr__ is never called.
> I need to avoid this, and return Worker instance's value instead of
> Base's default value.
> That is, in the last line of the example, I want: d.bar == 'Hello'
> How could it be done?
> --- cut ---
> # This class does the "real" work and I can modify it as needed
> class Worker:
> def __init__(self, foo, bar):
> self.foo = foo
> self.bar = bar
> # This is just a base class from which I must inherit but I can't modify it
> class Base:
> bar = None
> # This is a wrapper for Worker and I can modify it.
> # I want to get most attributes from Worker class
> # but for 'bar' I always get the default from Base,
> # its declaration there effectively hides the attribute
> # from the delegated Worked instance.
> class Derived(Base):
> def __init__(self, worker):
> self.worker = worker
> def __getattr__(self, name):
> return getattr(self.worker, name)
> w = Worker(1234, 'Hello')
> print 'w.foo', w.foo # prints 1234
> print 'w.bar', w.bar # prints Hello
> d = Derived(w)
> print 'd.foo',d.foo # prints 1234
> print 'd.bar',d.bar # prints None, I want to get Hello
As you already found out, d.bar looks up Base.bar, and __getattr__ isn't
invoked (since it is only called if an attribute is *not* found).
The easiest solution might be, to change the name of the attribute 'bar' in
Worker, since you can modify this class. If at all possible, make sure it has
no attribute names that are defined in Base also. Is this an acceptable
solution for you? It sounds cheesy, but it might be better than inventing all
kinds of twisted code constructs to get around this problem.
Hans (hans at zephyrfalcon.org)
More information about the Python-list