# Общее

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

Все объекты. Тип данных - по сути правило операций (функций) для одного типа. Для определения используемых при написании конструкций (например +, \*, ...) используются магические методы. Очень интересная возможность.

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

**1. Инициализация и управление объектом**

<table border="1" id="bkmrk-__new__%28cls%2C-...%29-%D0%A1%D0%BE" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 26.6072%;"></col><col style="width: 73.512%;"></col></colgroup><tbody><tr><td>\_\_new\_\_(cls, ...)</td><td>Создание экземпляра (до \_\_init\_\_)</td></tr><tr><td>\_\_init\_\_(self, ...)</td><td>Инициализация объекта</td></tr><tr><td>\_\_del\_\_(self)</td><td>При удалении объекта (деструктор, вызывается редко)</td></tr><tr><td>\_\_repr\_\_(self)</td><td>Для разработчиков (repr()) — однозначное представление</td></tr><tr><td>\_\_str\_\_(self)</td><td>Для пользователей (str(), print()) — читаемое представление</td></tr><tr><td>\_\_bytes\_\_(self)</td><td>bytes()</td></tr><tr><td>\_\_format\_\_(self, spec)</td><td>format() и f-строки</td></tr><tr><td>\_\_hash\_\_(self)</td><td>hash() (если None — объект нехэшируемый)</td></tr><tr><td>\_\_eq\_\_(self, other)</td><td>==</td></tr><tr><td>\_\_lt\_\_(self, other)</td><td>&lt;</td></tr><tr><td>\_\_le\_\_(self, other)</td><td>&lt;=</td></tr><tr><td>\_\_gt\_\_(self, other)</td><td>&gt;</td></tr><tr><td>\_\_ge\_\_(self, other)</td><td>&gt;=</td></tr><tr><td>\_\_bool\_\_(self)</td><td>bool(), if obj: (если нет — проверяет \_\_len\_\_)</td></tr><tr><td>\_\_len\_\_(self)</td><td>len()</td></tr><tr><td>\_\_contains\_\_(self, item)</td><td>in (если нет — перебирает через \_\_iter\_\_)</td></tr><tr><td>\_\_getitem\_\_(self, key)</td><td>self\[key\], for i in obj:</td></tr><tr><td>\_\_setitem\_\_(self, key, value)</td><td>self\[key\] = value</td></tr><tr><td>\_\_delitem\_\_(self, key)</td><td>del self\[key\]</td></tr><tr><td>\_\_iter\_\_(self)</td><td>Итератор (for x in obj:)</td></tr><tr><td>\_\_next\_\_(self)</td><td>next()</td></tr><tr><td>\_\_reversed\_\_(self)</td><td>reversed()</td></tr></tbody></table>

**2. Арифметические операторы**

Возвращается всегда новая переменная. Существует три варианта в случае арифметических операций:

- Базовый. Вызывается первым, для объекта слева. Объект справа может быть любого типа. Внутри нужно проверять принадлежность к классу для второго аргумента. В случае ошибки / несоответствия типов / ... вызывается NotImplemented. ```python
    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. Но если порядок не важен, можно сделать так: ```python
    class MyClass:
    ...
        def __radd__(self, other):
            return self.__add__(other)
    ```
- Существует способ записи например += Для него может быть отдельный (расширенный) метод. Если не определять, то вызывается соответствующий базовый метод. Можно менять сам объект. Обязательно возвращать объект.

<table border="1" id="bkmrk-__add__%28self%2C-other%29" style="border-collapse: collapse; width: 100%; height: 387.36px;"><colgroup><col style="width: 11.4422%;"></col><col style="width: 24.0763%;"></col><col style="width: 24.7914%;"></col><col style="width: 12.7563%;"></col><col style="width: 21.5703%;"></col><col style="width: 5.24434%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td style="height: 29.7969px;">Операция</td><td style="height: 29.7969px;">Базовые методы</td><td style="height: 29.7969px;">Правые версии</td><td>  
</td><td style="height: 29.7969px;">Расширенные версии</td><td style="height: 29.7969px;">  
</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">+</td><td style="height: 29.7969px;">\_\_add\_\_(self, other)</td><td style="height: 29.7969px;">\_\_radd\_\_(self, other)</td><td>other + self</td><td style="height: 29.7969px;">\_\_iadd\_\_(self, other)</td><td style="height: 29.7969px;">+=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">-</td><td style="height: 29.7969px;">\_\_sub\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rsub\_\_(self, other)</td><td>other - self</td><td style="height: 29.7969px;">\_\_isub\_\_(self, other)</td><td style="height: 29.7969px;">-=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\*</td><td style="height: 29.7969px;">\_\_mul\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rmul\_\_(self, other)</td><td>other \* self</td><td style="height: 29.7969px;">\_\_imul\_\_(self, other)</td><td style="height: 29.7969px;">\*=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">/</td><td style="height: 29.7969px;">\_\_truediv\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rtruediv\_\_(self, other)</td><td>other / self</td><td style="height: 29.7969px;">\_\_itruediv\_\_(self, other)</td><td style="height: 29.7969px;">/=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">//</td><td style="height: 29.7969px;">\_\_floordiv\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rfloordiv\_\_(self, other)</td><td>other // self</td><td style="height: 29.7969px;">\_\_ifloordiv\_\_(self, other)</td><td style="height: 29.7969px;">//=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">%</td><td style="height: 29.7969px;">\_\_mod\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rmod\_\_(self, other)</td><td>other % self</td><td style="height: 29.7969px;">\_\_imod\_\_(self, other)</td><td style="height: 29.7969px;">%=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\*\*, pow()</td><td style="height: 29.7969px;">\_\_pow\_\_(self, other\[, modulo\])</td><td style="height: 29.7969px;">\_\_rpow\_\_(self, other)</td><td>other \*\* self</td><td style="height: 29.7969px;">\_\_ipow\_\_(self, other)</td><td style="height: 29.7969px;">\*\*=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">-obj</td><td style="height: 29.7969px;">\_\_neg\_\_(self)</td><td style="height: 29.7969px;"> </td><td>  
</td><td style="height: 29.7969px;">  
</td><td style="height: 29.7969px;">  
</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">+obj</td><td style="height: 29.7969px;">\_\_pos\_\_(self)</td><td style="height: 29.7969px;"> </td><td>  
</td><td style="height: 29.7969px;">  
</td><td style="height: 29.7969px;">  
</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">abs()</td><td style="height: 29.7969px;">\_\_abs\_\_(self)</td><td style="height: 29.7969px;"> </td><td>  
</td><td style="height: 29.7969px;">  
</td><td style="height: 29.7969px;">  
</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">round()</td><td style="height: 29.7969px;">\_\_round\_\_(self\[, n\])</td><td style="height: 29.7969px;"> </td><td>  
</td><td style="height: 29.7969px;">  
</td><td style="height: 29.7969px;">  
</td></tr></tbody></table>

**3. Битовые операторы**

<table border="1" id="bkmrk-__and__%28self%2C-other%29" style="border-collapse: collapse; width: 100%; height: 208.578px;"><colgroup><col style="width: 12.8725%;"></col><col style="width: 23.1228%;"></col><col style="width: 25.7449%;"></col><col style="width: 27.6418%;"></col><col style="width: 10.6181%;"></col></colgroup><thead><tr style="height: 29.7969px;"><td style="height: 29.7969px;">Операция</td><td style="height: 29.7969px;">Базовые методы</td><td style="height: 29.7969px;">Правые версии</td><td style="height: 29.7969px;">Расширенные версии</td><td>  
</td></tr></thead><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">&amp;</td><td style="height: 29.7969px;">\_\_and\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rand\_\_(self, other)</td><td style="height: 29.7969px;">\_\_iand\_\_(self, other)</td><td>&amp;=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">|</td><td style="height: 29.7969px;">\_\_or\_\_(self, other)</td><td style="height: 29.7969px;">\_\_ror\_\_(self, other)</td><td style="height: 29.7969px;">\_\_ior\_\_(self, other)</td><td>|=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">^</td><td style="height: 29.7969px;">\_\_xor\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rxor\_\_(self, other)</td><td style="height: 29.7969px;">\_\_ixor\_\_(self, other)</td><td>^=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">&lt;&lt;</td><td style="height: 29.7969px;">\_\_lshift\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rlshift\_\_(self, other)</td><td style="height: 29.7969px;">\_\_ilshift\_\_(self, other)</td><td>&lt;&lt;=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">&gt;&gt;</td><td style="height: 29.7969px;">\_\_rshift\_\_(self, other)</td><td style="height: 29.7969px;">\_\_rrshift\_\_(self, other)</td><td style="height: 29.7969px;">\_\_irshift\_\_(self, other)</td><td>&gt;&gt;=</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">~</td><td style="height: 29.7969px;">\_\_invert\_\_(self)</td><td style="height: 29.7969px;"> </td><td style="height: 29.7969px;">  
</td><td>  
</td></tr></tbody></table>

**4. Методы для контекстного менеджера (``with``)**

<table border="1" id="bkmrk-__enter__%28self%29-%D0%92%D1%85%D0%BE%D0%B4" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 32.0597%;"></col><col style="width: 67.9403%;"></col></colgroup><tbody><tr><td>\_\_enter\_\_(self)</td><td>Вход в контекст</td></tr><tr><td>\_\_exit\_\_(self, exc\_type, exc\_val, exc\_tb)</td><td>Выход из контекста (с обработкой исключений)</td></tr></tbody></table>

**5. Работа с атрибутами**

<table border="1" id="bkmrk-__getattr__%28self%2C-na" style="border-collapse: collapse; width: 100%; height: 178.781px;"><colgroup><col style="width: 32.4405%;"></col><col style="width: 67.6786%;"></col></colgroup><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_getattr\_\_(self, name)</td><td style="height: 29.7969px;">при обращении к несуществующему атрибуту</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_setattr\_\_(self, name, value)</td><td style="height: 29.7969px;">при установке любого атрибута</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_delattr\_\_(self, name)</td><td style="height: 29.7969px;">del obj.name</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_getattribute\_\_(self, name)</td><td style="height: 29.7969px;">при обращении к ЛЮБОМУ атрибуту (осторожно, рекурсия!), редко используется</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_dir\_\_(self)</td><td style="height: 29.7969px;">dir()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_hasattr\_\_(self, name)</td><td style="height: 29.7969px;">hasattr() (не нужен — \_\_getattr\_\_ обработает)</td></tr></tbody></table>

**6. Вызов объекта как функции**

\_\_call\_\_(self, \*args, \*\*kwargs) # obj()

**7. Работа с классами и метаклассами**

<table border="1" id="bkmrk-__init_subclass__%28cl" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 33.2739%;"></col><col style="width: 66.8453%;"></col></colgroup><tbody><tr><td>\_\_init\_subclass\_\_(cls, \*\*kwargs)</td><td>при создании подкласса</td></tr><tr><td>\_\_set\_name\_\_(self, owner, name)</td><td>при создании дескриптора в классе</td></tr><tr><td>\_\_prepare\_\_(name, bases, \*\*kwargs)</td><td>метакласс: подготовка пространства имён</td></tr><tr><td>\_\_instancecheck\_\_(self, instance)</td><td>isinstance() (для метаклассов)</td></tr><tr><td>\_\_subclasscheck\_\_(self, subclass)</td><td>issubclass() (для метаклассов)</td></tr></tbody></table>

 **8. Дескрипторы (управление атрибутами другого класса)**

\_\_get\_\_(self, instance, owner) # получить атрибут  
\_\_set\_\_(self, instance, value) # установить атрибут  
\_\_delete\_\_(self, instance) # удалить атрибут

**9. Сериализация**

<table border="1" id="bkmrk-__reduce__%28self%29-pic" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 34.4644%;"></col><col style="width: 65.6548%;"></col></colgroup><tbody><tr><td>\_\_reduce\_\_(self)</td><td>pickle (возвращает (callable, args\[, state\]))</td></tr><tr><td>\_\_reduce\_ex\_\_(self, protocol)</td><td>расширенная версия для pickle</td></tr><tr><td>\_\_getstate\_\_(self)</td><td>что сохранять в pickle</td></tr><tr><td>\_\_setstate\_\_(self, state)</td><td>восстановление из pickle</td></tr></tbody></table>

**10. Математические и другие**

<table border="1" id="bkmrk-__complex__%28self%29-co" style="border-collapse: collapse; width: 100%; height: 297.969px;"><colgroup><col style="width: 34.7025%;"></col><col style="width: 65.4167%;"></col></colgroup><tbody><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_complex\_\_(self)</td><td style="height: 29.7969px;">complex()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_int\_\_(self)</td><td style="height: 29.7969px;">int()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_float\_\_(self)</td><td style="height: 29.7969px;">float()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_index\_\_(self)</td><td style="height: 29.7969px;">для преобразования в int (для срезов, bin(), hex())</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_trunc\_\_(self)</td><td style="height: 29.7969px;">math.trunc()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_floor\_\_(self)</td><td style="height: 29.7969px;">math.floor()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_ceil\_\_(self)</td><td style="height: 29.7969px;">math.ceil()</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_matmul\_\_(self, other)</td><td style="height: 29.7969px;">@ (матричное умножение в Python 3.5+)</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_rmatmul\_\_(self, other)</td><td style="height: 29.7969px;">right @</td></tr><tr style="height: 29.7969px;"><td style="height: 29.7969px;">\_\_imatmul\_\_(self, other)</td><td style="height: 29.7969px;">@=</td></tr></tbody></table>

**11. Асинхронные методы (async/await)**

<table border="1" id="bkmrk-__await__%28self%29-awai" style="border-collapse: collapse; width: 100%;"><colgroup><col style="width: 34.9405%;"></col><col style="width: 65.1786%;"></col></colgroup><tbody><tr><td>\_\_await\_\_(self)</td><td>await obj</td></tr><tr><td>\_\_aiter\_\_(self)</td><td>async for </td></tr><tr><td>\_\_anext\_\_(self)</td><td>async next()</td></tr><tr><td>\_\_aenter\_\_(self)</td><td>async with</td></tr><tr><td>\_\_aexit\_\_(self, exc\_type, exc\_val, exc\_tb)</td><td>async with exit</td></tr></tbody></table>

**Самые частые методы:**  
`\_\_init\_\_`, `\_\_str\_\_`, `\_\_repr\_\_` — 90% обычных классов  
`\_\_add\_\_`, `\_\_radd\_\_`, `\_\_iadd\_\_` — для своего класса с `+`  
`\_\_getitem\_\_`, `\_\_setitem\_\_`, `\_\_len\_\_` — чтобы объект вёл себя как коллекция  
`\_\_enter\_\_`, `\_\_exit\_\_` — для `with`  
`\_\_call\_\_` — сделать объект вызываемым (как функция)  
`\_\_eq\_\_`, `\_\_lt\_\_`, `\_\_hash\_\_` — для сравнения и словарей