tags:

views:

214

answers:

3

I want to have a python class that just acts as a wrapper for another python class.

Something like this

class xxx:
    name = property( fset=lambda self, v: setattr(self.inner, 'name', v), fget=lambda self: getattr(self.inner, 'name' ))

    def setWrapper( self, obj )
       self.inner = obj

So when someone says xxx().x = 'hello' I want it to set the value on xxx().inner.whatever and not xxx().x.

Is this possible, I have been trying lambdas, but to no avail.

Edit: Now my wife isn't rushing me to bed so I can flush out the code a bit more. I kind of had an idea about what you guys had below, but from the docs it seemed that you should avoid overriding __setattr__/__getattr__ and use property instead. If it is not possible to do this via the property function then I will use the __setattr__/__getattr__? Thanks

+5  A: 

This is where you use the __setattr__ and __getattr__ methods as documented here.

In short, if you do this:

class Wrapper(object):
    def __init__(self, wrapped):
       object.__setattr__(self, 'inner', wrapped)

    def __getattr__(self, attr):
        return getattr(self.inner, attr)

    def __setattr__(self, attr, value):
        setattr(self.inner, attr, value)

It should do what you're after. I'd highly recommend reading the docs linked to above.

EDIT: As pointed out, the original version fails due to __setattr__ being called unconditionally. I've updated this example. Note that this version is reliant on new-style class behaviour (as indicated by subclassing from object). For old-style I think you'd need to mess with __dict__ as follows:

class OldStyleWrapper:
    def __init__(self, wrapped):
        self.__dict__['inner'] = wrapped

    def __getattr__(self, attr):
        return getattr(self.inner, attr)

     def __setattr__(self, attr, value):
        setattr(self.inner, attr, value)
Benno
+4  A: 

As another answer said, __getattr__ and __setattr__ are the key, but you need care when using the latter...:

class Wrapper(object):
    def __init__(self, wrapped):
        object.__setattr__(self, 'inner', wrapped)

    def __getattr__(self, n):
        return getattr(self.inner, n)

    def __setattr__(self, n, value):
        setattr(self.inner, n, value)

You don't need precautions for self.inner access, because __getattr__ gets called only for attributes that aren't otherwise present; but __setattr__ gets called for EVERY attribute, so when you actually need to set self.inner (or any other attribute), you need to explicitly bypass __setattr__ (here I'm using object for the purpose, so I also inherit from object -- highly advisable anyway, in Python 2.*, otherwise you'd be making an "old-style class" [[the kind which AT LAST disappeared in Python 3]], which you really don't want to...;-).

Alex Martelli
Good point, I've edited my example to match yours. =)
Benno
A: 

I believe both Alex and Ben's answers should edit their setattr call as follows:

setattr(self.inner, n, value)
Simon Edwards
Sorry, I can't add comments to your posts guys.
Simon Edwards
I edited both answers
Anurag Uniyal