Создание класса-обёртки, которым удобно пользоваться - PullRequest
0 голосов
/ 30 января 2019

Чтобы отслеживать текущее и предыдущее значение определенных переменных, которые постоянно обновляются внутри цикла, я создал класс-обертку, который автоматически сохраняет старое значение внутри него при его обновлении:

class Updatable:
    def __init__(self, value=None, prev_value=None):
        # Initial conditions
        self._value = value
        self._prev_value = prev_value

    @property
    def value(self):
        return self._value

    @property
    def prev_value(self):
        return self._prev_value

    def update(self, new_value):
        self._prev_value = self._value
        self._value = new_value

    def has_value(self):
        return self._value is not None

    def has_prev_value(self):
        return self._prev_value is not None

Однако, чтобы она работала больше как обычная переменная, я хочу, чтобы все обычные операторы работали как положено (кроме присваивания, которое не может быть перегружено в Python), поэтому я определил многие специальныеметоды, которые может иметь класс:

    # Object representation
    def __str__(self):
        return str(self._value)

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

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

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

    def __reversed__(self):
        return reversed(self._value)

    # Arithmetic operations
    def __add__(self, other):
        return self._value + other

    def __sub__(self, other):
        return self._value - other

    def __mul__(self, other):
        return self._value * other

    def __matmul__(self, other):
        return self._value @ other

    def __truediv__(self, other):
        return self._value / other

    def __floordiv__(self, other):
        return self._value // other

    def __mod__(self, other):
        return self._value % other

    def __divmod__(self, other):
        return divmod(self._value, other)

    def __pow__(self, other, *args):
        return pow(self._value, other, *args)

    def __lshift__(self, other):
        return self._value << other

    def __rshift__(self, other):
        return self._value >> other

    def __and__(self, other):
        return self._value & other

    def __xor__(self, other):
        return self._value ^ other

    def __or__(self, other):
        return self._value | other

    # Comparison operators
    def __eq__(self, other):
        return self._value == other

    def __ne__(self, other):
        return self._value != other

    def __lt__(self, other):
        return self._value < other

    def __gt__(self, other):
        return self._value > other

    def __le__(self, other):
        return self._value <= other

    def __ge__(self, other):
        return self._value >= other

Хотя это может показаться большим количеством специальных методов, это все еще далеко от всех специальных методов , и поддержка всех их будет означать дажебольше кода, чем у меня уже есть.

Более того, определение этих специальных методов не позволяет мне использовать экземпляр в качестве второго операнда в двоичной операции.Например, хотя код

a = Updatable(2)
a + 3

работает, код

a = Updatable(2)
3 + a

приводит к ошибке TypeError: unsupported operand type(s) for +: 'int' and 'Updatable', которая нежелательна, если ее удобно использовать.

Существует ли какой-то другой подход к созданию класса-оболочки, который (почти) столь же удобен в использовании, как и использование типа данных, который он переносит напрямую (игнорируя тот факт, что при использовании обнаженного типа данных у вас не будет доступа кпредыдущее значение, если вы не храните его явно)?

1 Ответ

0 голосов
/ 30 января 2019

Добавьте это к определению вашего класса:

# Arithmetic operations
def __radd__(self, other):
    return other + self._value

def __add__(self, other):
    return self._value + other 

, а затем

a = Updatable(2)
3 + a

Вывод:

5

С исходным определением функции __add__:

a = Updatable(2)
a + 3

Вывод:

5
...