Математические методы
Вы знакомы с возможностями 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. Иначе должен вернуть пару из двух кортежей с преобразованными типами. Метод устарел служит только для обратной совместимости старого кода, вместо него надо использовать остальные методы приведения типов