Перейти к содержанию

Математические методы

Вы знакомы с возможностями Python как калькулятора. Числа можно складывать, умножать, проверять на больше или меньше, а также делать особые операции, типа объединения, возведения в степень или сдвиг. С помощью магических методов можно реализовать взаимодействие с объектами через знакомые операторы. Плюс заодно хотелось бы узнать, а какие вообще в Python есть такие операторы.

В этом уроке вы узнаете, что их так много, что можно было бы создать какой-то свой отдельный мир, описывающий взаимодействие объектов только с математическим (или похожими на них) операторами.

Для начала начнем с примера. Особенно красиво возможности использования оператора / использованы в библиотеке pathlib:

from pathlib import Path

home = Path('/home')
my_home = home / "xen"
notes = my_home / "notes.txt"
print(notes.resolve()) # /home/xen/notes.txt

with notes.open() as f:
    print(f.readline())

Объект Path реализовал магический метод __div__, что позволило записывать пути с помощью оператора деления и заодно визуально напоминает использование прямого слеша (знак наклоненной черты /), так же как это используется для записи путей в операционных системах Linux и macOS.

Большой список математических методов

Вот перечень методов для работы с математическими операторами:

  • __add__(self, other) — сложение +
  • __sub__(self, other) — вычитание -
  • __mul__(self, other) — умножение *
  • __floordiv__(self, other) — целочисленное деление //
  • __div__(self, other) — деление /
  • __truediv__(self, other) — настоящее (true) деление, которое включается с помощью from __future__ import division, подробнее в pep-0238
  • __mod__(self, other) — деление по модулю %.
  • __divmod__(self, other) — поддержка встроенной функции divmod()
  • __pow__(self, other) — возведение в степень **
  • __lshift__(self, other) — смещение влево <<
  • __rshift__(self, other) — смещение вправо >>
  • __and__(self, other) — бинарное И &
  • __or__(self, other) — бинарное ИЛИ |
  • __xor__(self, other) — бинарное XOR ^

Все бы хорошо, но эти методы подразумевают, что объект которых их реализует находится слева от оператора. А что же будет если его расположить справа? Для этих случаев создан такой же набор "правых" магических методов:

  • __radd__(self, other) — правое сложение +
  • __rsub__(self, other) — правое вычитание -
  • __rmul__(self, other) — правое умножение *
  • __rfloordiv__(self, other) — правое целочисленное деление //
  • __rdiv__(self, other) — правое деление /
  • __rtruediv__(self, other) — правое настоящее (true) деление, которое включается с помощью from __future__ import division
  • __rmod__(self, other) — правое деление по модулю %.
  • __rdivmod__(self, other) — правая поддержка встроенной функции для случая, когда вызывается divmod(other, self)
  • __rpow__(self, other) — правое возведение в степень **
  • __rrlshift__(self, other) — правое смещение влево <<
  • __rrshift__(self, other) — правое смещение вправо >>
  • __rand__(self, other) — правое бинарное И &
  • __ror__(self, other) — правое бинарное ИЛИ |
  • __rxor__(self, other) — правое бинарное XOR ^

В дополнение к этом набору еще есть операторы присвоения:

  • __iadd__(self, other) — присвоение со сложением +=
  • __isub__(self, other) — присвоение с вычитанием -=
  • __imul__(self, other) — присвоение с умножением *=
  • __ifloordiv__(self, other) — присвоение с целочисленным делением //=
  • __idiv__(self, other) — присвоение c делением /=
  • __itruediv__(self, other) — присвоение настоящим делением. Работает только если сначала выполнить from __future__ import division.
  • __imod__(self, other) — присвоение с делением по модулю %=
  • __ipow__(self, other) — присвоение c возведением в степень **=
  • __ilshift__(self, other) — присвоение левым бинарным смещением <<=
  • __irshift__(self, other) — присвоение правым бинарным смещением >>=
  • __iand__(self, other) — присвоение с бинарным И &=
  • __ior__(self, other) — присвоение с бинарным ИЛИ |=
  • __ixor__(self, other) — присвоение c бинарным XOR ^=

Теперь точно должно быть понятнее как работает библиотека pathlib.

Приведение к типу

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

Если ваш объект подразумевает возможность преобразование в числовые типы, то реализовав необходимые методы вы сможете использовать int(obj). А не реализация их сделает это преобразование невозможным:

  • __int__(self) — Поддержка конвертации в int.
  • __long__(self) — Поддержка конвертации в long.
  • __float__(self) — Поддержка конвертации в float.
  • __complex__(self) — Поддержка конвертации в complex.
  • __oct__(self) — Поддержка конвертации в octal.
  • __hex__(self) — Поддержка конвертации в hexadecimal.
  • __index__(self) — Поддержка конвертации в конвертации в int когда объект используется в качестве элемента среза (slice). Если вы создадите свой отдельный числовой тип и захотите его использовать в качестве элемента среза, то него должен быть реализован метод __index__. Например, obj[myint:myotherint]
  • __trunc__(self) — Вызывается функцией math.trunc(self)
  • __coerce__(self, other) — особенный метод, для арифметики смешанных типов. Если для входящего типа невозможно приведение типа, то этот метод должен вернуть None. Иначе должен вернуть пару из двух кортежей с преобразованными типами. Метод устарел служит только для обратной совместимости старого кода, вместо него надо использовать остальные методы приведения типов