views:

43

answers:

3

I have a class called Cell:

class Cell:

    def __init__(self, value, color, size):
        self._value = value
        self._color = color
        self._size = size

    # and other methods...

Cell._value will store a string, integer, etc. (whatever I am using that object for). I want all default methods that would normally use the "value" of an object to use <Cell object>._value so that I can do:

>>> c1 = Cell(7, "blue", (5,10))
>>> c2 = Cell(8, "red", (10, 12))
>>> print c1 + c2
15

>>> c3 = Cell(["ab", "cd"], "yellow", (50, 50))
>>> print len(c3), c3
2 ['ab', 'cd']

# etc.

I could override all the default methods:

class Cell:

    def __init__(self, value, color, size):
        # ...

    def __repr__(self):
        return repr(self._value)

    def __str__(self):
        return str(self._value)

    def __getitem__(self, key):
        return self._value[key]

    def __len__(self):
        return len(self._value)

    # etc.

...but is there an easier way?

A: 

If you want it to do customized behavior you're going to have to customize that behavior. There's no getting around it.

wheaties
A: 

You need to overload the __add__ method in order to get the c1 + c2 behavior you want.

See here for info on what they all are.

Daenyth
+1  A: 

If I understand you correctly, you're looking for an easy way to delegate an object's method to a property of that object?

You can avoid some of the repetitiveness by defining a decorator:

def delegate(method, prop):
    def decorate(cls):
        setattr(cls, method,
            lambda self, *args, **kwargs:
                getattr(getattr(self, prop), method)(*args, **kwargs))
        return cls
    return decorate

You can then apply the decorator for each method you want delegated:

@delegate('__len__', '_content')
@delegate('__getitem__', '_content')
class MyList(object):
    def __init__(self, content):
        self._content = content

spam = MyList([1,2,3,4,5])

len(spam) # prints "5"

spam[0] # prints "1"

You could probably simplify it further by modifying the decorator to take multiple method names as argument.

If you want your class to act as a full wrapper, you could probably override the class's __getattr__ method to check the wrapped object before failing. That would emulate the behaviour of subclasses without actual inheritance.

Alan
I think overriding `__getattr__` is closer to what I'm looking for but I see the value in the decorator option as well. Now I just need to understand the different between `__getattr__` and `__getattribute__`: http://docs.python.org/reference/datamodel.html#object.__getattribute__
justus87