Документация по Python

Перегрузка операторов в Python

В: Документация по Python

Методы магии / Дандер

Магические (также называемые dunder как аббревиатура от двойного подчеркивания) методы в Python имеют ту же цель, что и перегрузка операторов в других языках. Они позволяют классу определять свое поведение, когда он используется в качестве операнда в выражениях унарных или бинарных операторов. Они также служат реализациями, вызываемыми некоторыми встроенными функциями.

Рассмотрим эту реализацию двумерных векторов.

import math

class Vector(object):
    # instantiation
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # unary negation (-v)
    def __neg__(self):
        return Vector(-self.x, -self.y)

    # addition (v + u)
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    # subtraction (v - u)
    def __sub__(self, other):
        return self + (-other)

    # equality (v == u)
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    # abs(v)
    def __abs__(self):
        return math.hypot(self.x, self.y)

    # str(v)
    def __str__(self):
        return '<{0.x}, {0.y}>'.format(self)

    # repr(v)
    def __repr__(self):
        return 'Vector({0.x}, {0.y})'.format(self)

Теперь можно , естественно , использовать экземпляры Vector класса в различных выражениях.

v = Vector(1, 4)
u = Vector(2, 0)

u + v           # Vector(3, 4)
print(u + v)    # "<3, 4>" (implicit string conversion)
u - v           # Vector(1, -4)
u == v          # False
u + v == v + u  # True
abs(u + v)      # 5.0 

Обработка невыполненного поведения

Если ваш класс не реализует конкретный перегруженный оператор для типов аргументов , предоставленных, он должен return NotImplemented (обратите внимание , что это специальная константа , не то же самое , как NotImplementedError ). Это позволит Python попробовать другие методы, чтобы заставить работу работать:

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

Например, если x + y , если x.__add__(y) возвращает невыполненным, y.__radd__(x) попытка вместо этого.

class NotAddable(object):

    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        return NotImplemented


class Addable(NotAddable):

    def __add__(self, other):
        return Addable(self.value + other.value)

    __radd__ = __add__

Как это отражается метод , который мы должны реализовать __add__ и __radd__ получить ожидаемое поведение во всех случаях; к счастью, так как они оба делают одно и то же в этом простом примере, мы можем воспользоваться ярлыком.

В использовании:

>>> x = NotAddable(1)
>>> y = Addable(2)
>>> x + x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'NotAddable' and 'NotAddable'
>>> y + y
<so.Addable object at 0x1095974d0>
>>> z = x + y
>>> z
<so.Addable object at 0x109597510>
>>> z.value
3

Перегрузка оператора

Ниже приведены операторы, которые могут быть перегружены в классах, а также необходимые определения методов и пример использования оператора в выражении.

NB Использование other в качестве имени переменной не является обязательным, но считается нормой.

Оператора Метод Выражение
Сложение + __add__(self, other) a1 + a2
Вычитание - __sub__(self, other) a1 - a2
Умножение * __mul__(self, other) a1 * a2
Умножение матриц __matmul__(self,other) a1 @ a2 (Python 3.5)
Деление / __div__(self, other) a1 / a2 (Python 2)
Деление / __truediv(self, other) a1 / a2 (Python 3)
Целочисленное деление // __floordiv__(self, other) a1 // a2
Модуло / Остаток __mod__(self, other) a1 % a2
Степень __pow__(self, other[, modulo]) a1 ** a2
Побитовый сдвиг влево << __lshift__(self, other) a1 << a2
Побитовый сдвиг вправо >> __rshift__(self, other) a1 >> a2
Побитовое сложение & __add__(self, other) a1 & a2
Побитовое исключающее ИЛИ ^ __xor__(self, other) a1 ^ a2
Побитовое | ИЛИ __or__(self, other) a1|a2
Отрицание - __neg__(self) -a1
Положительное + __pos__(self) +a1
Побитовое НЕ ~ __invert__(self) ~a1
Меньше чем < __lt__(self, other) a1 < a2
Меньше или равно <= __le__(self, other) a1 <= a2
Равно == __eq__(self, other) a1 == a2
Не равно >= __ne__(self, other) a1 != a2
Больше чем > __gt__(self, other) a1 > a2
Больше или равно => __ge__(self, other) a1 >= a2
Индекс [index] __getitem__(self, index) a1[index]
Оператор в in __contains__(self, other) a2 in a2
Вызов функции (*args, ...) __call__(self, *args, **kwargs) a1(*args, **kwargs)

Необязательный параметр по modulo для __pow__ используется только в pow встроенной функции.

Каждый из методов , соответствующих бинарный оператор имеет соответствующий «правильный» метод , который начать с __r , например __radd__ :

 class A:
    def __init__(self, a):
        self.a = a
    def __add__(self, other):
        return self.a + other
    def __radd__(self, other):
        print("radd")
        return other + self.a

A(1) + 2  # Out:  3
2 + A(1)  # prints radd. Out: 3

 

а также соответствующая версия Inplace, начиная с __i :

 class B:
    def __init__(self, b):
        self.b = b
    def __iadd__(self, other):
        self.b += other
        print("iadd")
        return self

b = B(2)
b.b       # Out: 2
b += 1    # prints iadd
b.b       # Out: 3

 

Поскольку в этих методах нет ничего особенного, многие другие части языка, части стандартной библиотеки и даже сторонние модули самостоятельно добавляют магические методы, такие как методы для приведения объекта к типу или проверки свойств объекта. Например, встроенная str() вызов функции объекта __str__ метод, если он существует. Некоторые из этих видов использования перечислены ниже.

Id Метод Выражение
Кастинг для int __int__(self) int(a1)
Абсолютная функция __abs__(self) abs(a1)
Кастинг для str __str__(self) str(a1)
Кастинг для unicode __unicode__(self) unicode(a1) python 2
Строковое представление __repr__(self) repr(a1)
Приведение к bool __nonzero__(self) bool(a1)
Форматирование строки __format__(self, formatstr) "Hi {:abc}".format(a1)
Хэшировние __hash__(self) hash(a1)
Длина __len__(self) len(a1)
Округление __round__(self) round(a1)
Обратное округление __reversed__(self) reversed(a1)
Floor __floor__(self) math.floor(a1)
Ceiling __ceil__(self) math.ceil(a1)

Есть также специальные методы __enter__ и __exit__ для менеджеров контекста, и многих других.

Еще от кодкамп
Замечательно! Вы успешно подписались.
Добро пожаловать обратно! Вы успешно вошли
Вы успешно подписались на кодкамп.
Срок действия вашей ссылки истек.
Ура! Проверьте свою электронную почту на наличие волшебной ссылки для входа.
Успех! Ваша платежная информация обновлена.
Ваша платежная информация не была обновлена.