Простой способ переопределить стандартные методы в пользовательских классах Python? - PullRequest
6 голосов
/ 15 сентября 2010

У меня есть класс Cell:

class Cell:

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

    # and other methods...

Cell._value будет хранить строку, целое число и т. Д. (Для чего бы я ни использовал этот объект). Я хочу, чтобы все методы по умолчанию, которые обычно использовали бы «значение» объекта для использования <Cell object>._value, чтобы я мог сделать:

>>> 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.

Я могу переопределить все методы по умолчанию:

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.

... но есть ли более простой способ?

Ответы [ 2 ]

11 голосов
/ 16 сентября 2010

Если я вас правильно понимаю, вы ищете простой способ делегировать метод объекта свойству этого объекта?

Вы можете избежать некоторых повторений, определив декоратор:

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

Затем вы можете применить декоратор для каждого метода, который вы хотите делегировать:

@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"

Возможно, вы могли бы еще больше упростить его, изменив декоратор так, чтобы в качестве аргумента принимались несколько имен методов.

Если вы хотите, чтобы ваш класс действовал как полная обертка, вы, возможно, могли бы переопределить метод __getattr__ класса, чтобы проверить завернутый объект перед сбоем. Это подражало бы поведению подклассов без фактического наследования.

0 голосов
/ 15 сентября 2010

Вам необходимо перегрузить метод __add__, чтобы получить желаемое поведение c1 + c2.

См. здесь для получения информации о том, чем они все являются.

...