Default attribute in base class precludes delegation

Bengt Richter bokr at oz.net
Fri Dec 19 06:41:01 CET 2003


On Fri, 19 Dec 2003 00:44:28 -0300, Gabriel Genellina <gagenellina at softlab.com.ar> wrote:

>Hi
>
>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.
In what sense a "wrapper"?
>
>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.
Why do you (think you) need an explicit __getattr__ ? Usually there's better ways.

>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:
 class Worker(object):
>     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):
 class Derived(Worker, Base):
      """never mind any methods at this point yet"""

>     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)
 d = Derived(6578, 'Goodbye')

>print 'd.foo',d.foo     # prints 1234
>print 'd.bar',d.bar     # prints None, I want to get Hello
>
>--- cut ---

Does this do anything for you? (you could inherit differently than below too, of course)

====< genellina.py >=========================================================================
# This class does the "real" work and I can modify it as needed
class Worker(object):
    def __init__(self, foo, bar):
        print 'Worker init: Initializing %s instance' % self.__class__.__name__
        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:
    def __init__(self,*args, **kw): print 'Base init:', args, kw
    bar = None
    baz = 'Base baz'

# This is a wrapper for Worker and I can modify it.
# I want to get most attributes from Worker class
##### why not just inherit them from ^^^^^^^^^^^^ ?
# but for 'bar' I always get the default from Base,
# its declaration there effectively hides the attribute
# from the delegated Worked instance.

class Derived(Worker, Base):
    """dummy until something to do"""

if __name__ == '__main__':
    w = Worker(1234, 'Hello')
    print 'w.foo of %s instance: %s' %(w.__class__.__name__, w.foo)     # prints 1234 now
    print 'w.bar of %s instance: %s' %(w.__class__.__name__, w.bar)     # prints Hello now
    d = Derived(5678, 'Goodbye') #w)
    print 'd.foo of %s instance: %s' %(d.__class__.__name__, d.foo)     # prints 5678 now
    print 'd.bar of %s instance: %s' %(d.__class__.__name__, d.bar)     # prints Goodbye now
    print 'd.baz of/via %s instance: %s' %(d.__class__.__name__, d.baz)
    d.baz = 'd instance baz'
    print 'd.baz of/via %s instance: %s' %(d.__class__.__name__, d.baz)
=============================================================================================

Result:

[21:52] C:\pywk\clp>genellina.py
Worker init: Initializing Worker instance
w.foo of Worker instance: 1234
w.bar of Worker instance: Hello
Worker init: Initializing Derived instance
d.foo of Derived instance: 5678
d.bar of Derived instance: Goodbye
d.baz of/via Derived instance: Base baz
d.baz of/via Derived instance: d instance baz

Or do you actually need to have different unknown types of workers so you can't inherit?

Regards,
Bengt Richter




More information about the Python-list mailing list