From: Ulrich Eckhardt on
Hi!

I have an extension module (a plugin written with Boost.Python) and around
that a wrapper class that adapts a few things. Since the module is a
plugin, there are multiple implementations of this. What I'm currently
doing is this:

plugin = __import__(plugin_name)

class PluginWrapper(plugin.PluginClass):
...

This means that the definition of class PluginWrapper actually depends on
the previously loaded module. What I would like to do is to define the
wrapper just once and instead pass the plugin module to the constructor:

class PluginWrapper(object):
...
plugin = __import__(plugin_name)
instance = PluginWrapper(plugin)


Now, I use the wrapper to make some function more friendly (e.g. default
parameters, keyword-parameters, wrapping raw handles) but I want other
functions from the baseclass to remain untouched. If I use a baseclass,
this lookup is automatic. However, when I pass the instance to the
constructor, I have to store it in a member, and then I have to add code
for every function only to delegate it to that member.

Is there an easy and generic way out of this?

Thanks!

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932

From: Peter Otten on
Ulrich Eckhardt wrote:

> Hi!
>
> I have an extension module (a plugin written with Boost.Python) and around
> that a wrapper class that adapts a few things. Since the module is a
> plugin, there are multiple implementations of this. What I'm currently
> doing is this:
>
> plugin = __import__(plugin_name)
>
> class PluginWrapper(plugin.PluginClass):
> ...
>
> This means that the definition of class PluginWrapper actually depends on
> the previously loaded module. What I would like to do is to define the
> wrapper just once and instead pass the plugin module to the constructor:
>
> class PluginWrapper(object):
> ...
> plugin = __import__(plugin_name)
> instance = PluginWrapper(plugin)
>
>
> Now, I use the wrapper to make some function more friendly (e.g. default
> parameters, keyword-parameters, wrapping raw handles) but I want other
> functions from the baseclass to remain untouched. If I use a baseclass,
> this lookup is automatic. However, when I pass the instance to the
> constructor, I have to store it in a member, and then I have to add code
> for every function only to delegate it to that member.
>
> Is there an easy and generic way out of this?

Use getattr()

>>> class W(object):
.... def __init__(self, wrapped): self._wrapped = wrapped
.... def __getattr__(self, name):
.... return getattr(self._wrapped, name)
....
>>> class A(object):
.... def hello(self): print "hello"
....
>>> a = A()
>>> w = W(a)
>>> w.hello()
hello

However, with newsytle classes this doesn't work for __special__ methods

>>> w.__str__()
'<__main__.W object at 0x7f04ef2d4c50>'

Peter
From: Chris Rebert on
On Tue, Aug 10, 2010 at 2:01 AM, Ulrich Eckhardt
<eckhardt(a)satorlaser.com> wrote:
> Hi!
>
> I have an extension module (a plugin written with Boost.Python) and around
> that a wrapper class that adapts a few things. Since the module is a
> plugin, there are multiple implementations of this. What I'm currently
> doing is this:
>
>  plugin = __import__(plugin_name)
>
>  class PluginWrapper(plugin.PluginClass):
>     ...
>
> This means that the definition of class PluginWrapper actually depends on
> the previously loaded module. What I would like to do is to define the
> wrapper just once and instead pass the plugin module to the constructor:
>
>  class PluginWrapper(object):
>    ...
>  plugin = __import__(plugin_name)
>  instance = PluginWrapper(plugin)
>
>
> Now, I use the wrapper to make some function more friendly (e.g. default
> parameters, keyword-parameters, wrapping raw handles) but I want other
> functions from the baseclass to remain untouched. If I use a baseclass,
> this lookup is automatic. However, when I pass the instance to the
> constructor, I have to store it in a member, and then I have to add code
> for every function only to delegate it to that member.
>
> Is there an easy and generic way out of this?

Create the subclass(es) dynamically:

def wrap(plug_in):
class PluginWrapper(plug_in.PluginClass):
...
return PluginWrapper

plugin = __import__(plugin_name)
WrappedPlugin = wrap(plugin)

Cheers,
Chris
--
http://blog.rebertia.com
From: Ulrich Eckhardt on
Peter Otten wrote:
> Use getattr()
>
>>>> class W(object):
> ... def __init__(self, wrapped): self._wrapped = wrapped
> ... def __getattr__(self, name):
> ... return getattr(self._wrapped, name)
> ...

I thought there was something like this, thanks! :)

When I read this, I thought "OK, now I only have check first if the
attribute can be looked up in 'self' first", but even that isn't the case.
I tried it and added another function to class W above, which I can call
just as if it was defined in _wrapped, so obviously (?) the __getattr__
lookup isn't done there.

So, short follow-up question: Why does this work?

Uli

--
Sator Laser GmbH
Geschäftsführer: Thorsten Föcking, Amtsgericht Hamburg HR B62 932

From: Peter Otten on
Ulrich Eckhardt wrote:

> Peter Otten wrote:
>> Use getattr()
>>
>>>>> class W(object):
>> ... def __init__(self, wrapped): self._wrapped = wrapped
>> ... def __getattr__(self, name):
>> ... return getattr(self._wrapped, name)
>> ...
>
> I thought there was something like this, thanks! :)
>
> When I read this, I thought "OK, now I only have check first if the
> attribute can be looked up in 'self' first", but even that isn't the case.

The getattr() call inside __getattr__() raises an AttributeError if it can't
find an attribute called name in self._wrapped. This very thing you'd have
to do if you wanted to signal that an attribute doesn't exist, like in

>>> class A:
.... def __getattr__(self, name):
.... if name == "foo": return 42
.... raise AttributeError
....
>>> a = A()
>>> a.foo
42
>>> a.bar
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getattr__
AttributeError

> I tried it and added another function to class W above, which I can call
> just as if it was defined in _wrapped, so obviously (?) the __getattr__
> lookup isn't done there.
>
> So, short follow-up question: Why does this work?

__getattr__() is a fallback that is only tried when the normal lookup fails.
If you need to intercept every attribute lookup use __getattribute__()
instead:

>> class A(object):
.... def __getattr__(self, name):
.... print "__getattr__(%r)" % name
.... return 42
.... def __getattribute__(self, name):
.... print "__getattribute__(%r)" % name
.... return super(A, self).__getattribute__(name)
....
>>> a = A()
>>> a.foo = "yadda"
>>> a.foo
__getattribute__('foo')
'yadda'
>>> a.bar
__getattribute__('bar')
__getattr__('bar')
42

Peter