Общее
Магические методы
Все объекты. Тип данных - по сути правило операций (функций) для одного типа. Для определения используемых при написании конструкций (например +, *, ...) используются магические методы. Очень интересная возможность.
Магические методы
1. Инициализация и управление объектом
| __new__(cls, ...) | Создание экземпляра (до __init__) |
| __init__(self, ...) | Инициализация объекта |
| __del__(self) | При удалении объекта (деструктор, вызывается редко) |
| __repr__(self) | Для разработчиков (repr()) — однозначное представление |
| __str__(self) | Для пользователей (str(), print()) — читаемое представление |
| __bytes__(self) | bytes() |
| __format__(self, spec) | format() и f-строки |
| __hash__(self) | hash() (если None — объект нехэшируемый) |
| __eq__(self, other) | == |
| __lt__(self, other) | < |
| __le__(self, other) | <= |
| __gt__(self, other) | > |
| __ge__(self, other) | >= |
| __bool__(self) | bool(), if obj: (если нет — проверяет __len__) |
| __len__(self) | len() |
| __contains__(self, item) | in (если нет — перебирает через __iter__) |
| __getitem__(self, key) | self[key], for i in obj: |
| __setitem__(self, key, value) | self[key] = value |
| __delitem__(self, key) | del self[key] |
| __iter__(self) | Итератор (for x in obj:) |
| __next__(self) | next() |
| __reversed__(self) | reversed() |
2. Арифметические операторы
Возвращается всегда новая переменная. Существует три варианта в случае арифметических операций:
- Базовый. Вызывается первым, для объекта слева. Объект справа может быть любого типа. Внутри нужно проверять принадлежность к классу для второго аргумента. В случае ошибки / несоответствия типов / ... вызывается NotImplemented.
class MyClass: def __add__(self, other): if isinstance(other, MyClass): return MyClass(self.value + other.value) elif isinstance(other, (int, float)): return MyClass(self.value + other) else: # Не знаю, что делать return NotImplemented - Если был вызван NotImplemented, право сделать что-то передается объекту справа (правые версии). Если правая версия не определена, то будет TypeError. Но если порядок не важен, можно сделать так:
class MyClass: ... def __radd__(self, other): return self.__add__(other) - Существует способ записи например += Для него может быть отдельный (расширенный) метод. Если не определять, то вызывается соответствующий базовый метод. Можно менять сам объект. Обязательно возвращать объект.
| Операция | Базовые методы | Правые версии | Расширенные версии | ||
| + | __add__(self, other) | __radd__(self, other) | other + self | __iadd__(self, other) | += |
| - | __sub__(self, other) | __rsub__(self, other) | other - self | __isub__(self, other) | -= |
| * | __mul__(self, other) | __rmul__(self, other) | other * self | __imul__(self, other) | *= |
| / | __truediv__(self, other) | __rtruediv__(self, other) | other / self | __itruediv__(self, other) | /= |
| // | __floordiv__(self, other) | __rfloordiv__(self, other) | other // self | __ifloordiv__(self, other) | //= |
| % | __mod__(self, other) | __rmod__(self, other) | other % self | __imod__(self, other) | %= |
| **, pow() | __pow__(self, other[, modulo]) | __rpow__(self, other) | other ** self | __ipow__(self, other) | **= |
| -obj | __neg__(self) | ||||
| +obj | __pos__(self) | ||||
| abs() | __abs__(self) | ||||
| round() | __round__(self[, n]) |
3. Битовые операторы
| Операция | Базовые методы | Правые версии | Расширенные версии | |
| & | __and__(self, other) | __rand__(self, other) | __iand__(self, other) | &= |
| | | __or__(self, other) | __ror__(self, other) | __ior__(self, other) | |= |
| ^ | __xor__(self, other) | __rxor__(self, other) | __ixor__(self, other) | ^= |
| << | __lshift__(self, other) | __rlshift__(self, other) | __ilshift__(self, other) | <<= |
| >> | __rshift__(self, other) | __rrshift__(self, other) | __irshift__(self, other) | >>= |
| ~ | __invert__(self) |
4. Методы для контекстного менеджера (``with``)
| __enter__(self) | Вход в контекст |
| __exit__(self, exc_type, exc_val, exc_tb) | Выход из контекста (с обработкой исключений) |
5. Работа с атрибутами
| __getattr__(self, name) | при обращении к несуществующему атрибуту |
| __setattr__(self, name, value) | при установке любого атрибута |
| __delattr__(self, name) | del obj.name |
| __getattribute__(self, name) | при обращении к ЛЮБОМУ атрибуту (осторожно, рекурсия!), редко используется |
| __dir__(self) | dir() |
| __hasattr__(self, name) | hasattr() (не нужен — __getattr__ обработает) |
6. Вызов объекта как функции
__call__(self, *args, **kwargs) # obj()
7. Работа с классами и метаклассами
| __init_subclass__(cls, **kwargs) | при создании подкласса |
| __set_name__(self, owner, name) | при создании дескриптора в классе |
| __prepare__(name, bases, **kwargs) | метакласс: подготовка пространства имён |
| __instancecheck__(self, instance) | isinstance() (для метаклассов) |
| __subclasscheck__(self, subclass) | issubclass() (для метаклассов) |
8. Дескрипторы (управление атрибутами другого класса)
__get__(self, instance, owner) # получить атрибут
__set__(self, instance, value) # установить атрибут
__delete__(self, instance) # удалить атрибут
9. Сериализация
| __reduce__(self) | pickle (возвращает (callable, args[, state])) |
| __reduce_ex__(self, protocol) | расширенная версия для pickle |
| __getstate__(self) | что сохранять в pickle |
| __setstate__(self, state) | восстановление из pickle |
10. Математические и другие
| __complex__(self) | complex() |
| __int__(self) | int() |
| __float__(self) | float() |
| __index__(self) | для преобразования в int (для срезов, bin(), hex()) |
| __trunc__(self) | math.trunc() |
| __floor__(self) | math.floor() |
| __ceil__(self) | math.ceil() |
| __matmul__(self, other) | @ (матричное умножение в Python 3.5+) |
| __rmatmul__(self, other) | right @ |
| __imatmul__(self, other) | @= |
11. Асинхронные методы (async/await)
| __await__(self) | await obj |
| __aiter__(self) | async for |
| __anext__(self) | async next() |
| __aenter__(self) | async with |
| __aexit__(self, exc_type, exc_val, exc_tb) | async with exit |
Самые частые методы:
`__init__`, `__str__`, `__repr__` — 90% обычных классов
`__add__`, `__radd__`, `__iadd__` — для своего класса с `+`
`__getitem__`, `__setitem__`, `__len__` — чтобы объект вёл себя как коллекция
`__enter__`, `__exit__` — для `with`
`__call__` — сделать объект вызываемым (как функция)
`__eq__`, `__lt__`, `__hash__` — для сравнения и словарей