Default attribute in base class precludes delegation

G

Gabriel Genellina

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.

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

--- cut ---

Gabriel Genellina
Softlab SRL
 
B

Bengt Richter

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
 
G

Gabriel Genellina

In what sense a "wrapper"?

In fact it's an Adapter: it contains a reference to the Worker -and
delegates most method calls to it- also providing the interfase expected
from Base.
instance.
Why do you (think you) need an explicit __getattr__ ? Usually there's
better ways.
How?

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

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

Oh, thanks but that won't work. There are many types of Workers, chosen at
run time, that's why I can't simply inherit and have to use delegation.


Gabriel Genellina
Softlab SRL
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top