Класс и экземпляр
class Account:
currency = "RUB" # атрибут класса — общий для всех
def __init__(self, owner):
self.owner = owner # атрибут экземпляра
self.balance = 0
self — ссылка на текущий экземпляр, Python передаёт её первым аргументом. __init__ не создаёт объект, а заполняет уже созданный — создаёт __new__. Изменяемый атрибут класса (items = []) общий для всех экземпляров — частая ошибка.
Магические методы
Методы вида __имя__ подключают объект к операциям языка: __len__ к len(), __iter__ к for, __eq__ к ==, __enter__ и __exit__ к with, __call__ к вызову.
__repr__— однозначное представление для разработчика:Account(owner='Анна');__str__— читаемое для человека.printберёт__str__, а если его нет —__repr__. Поэтому__repr__пишут всегда.
property
@property превращает метод в атрибут: снаружи obj.area, внутри — вычисление или проверка.
class Rect:
def __init__(self, w, h):
self.w, self.h = w, h
@property
def area(self):
return self.w * self.h
@x.setter добавляет проверку при присваивании. В Python не пишут get_x() и set_x() заранее: начинают с обычного атрибута и заменяют его на property, когда понадобится, — вызывающий код не меняется.
staticmethod и classmethod
@classmethod получает класс (cls) — это способ писать альтернативные конструкторы: User.from_json(data). При наследовании cls будет подклассом, и создастся объект нужного типа. @staticmethod не получает ничего — это обычная функция, логически относящаяся к классу.
Наследование и MRO
MRO — порядок поиска метода по иерархии, его строит алгоритм C3: Class.__mro__. super() вызывает следующий класс в MRO, а не просто родителя — при множественном наследовании это разные вещи. В «ромбе» общий предок встречается в MRO один раз, и каждый класс вызывается ровно однажды, если все используют super().
dataclass, namedtuple и Pydantic
| Что даёт | Когда | |
|---|---|---|
@dataclass | __init__, __repr__, __eq__ по полям; без проверки типов | внутренние структуры |
namedtuple | неизменяемый кортеж с именами полей | лёгкие записи, распаковка |
| Pydantic | проверка и преобразование данных, JSON | внешние данные: API, конфиги |
from dataclasses import dataclass, field
@dataclass(frozen=True, slots=True)
class Point:
x: float
y: float
tags: list[str] = field(default_factory=list)
frozen=True — неизменяемость и согласованный хеш, slots=True — экономия памяти. Изменяемое значение по умолчанию — только через default_factory.
ABC и Protocol
ABC — номинальная типизация: класс явно наследует абстрактный, и пока не реализованы все @abstractmethod, экземпляр не создать. Protocol — структурная: подходит любой класс с нужными методами, без наследования, а проверяет это mypy или pyright. Protocol удобен для чужих классов, которые нельзя изменить; ABC может нести общую реализацию.
Метаклассы
Класс — тоже объект, метакласс — класс класса, по умолчанию type. Метаклассы используют ABCMeta, Enum, модели Django и SQLAlchemy. В своём коде регистрацию и проверку подклассов почти всегда проще сделать через __init_subclass__ или декоратор класса. «Если вы сомневаетесь, нужен ли метакласс, — он не нужен».
Что запомнить
__init__заполняет объект, создаёт его__new__.__repr__пишут всегда.- property вместо геттеров и сеттеров.
super()— следующий в MRO, а не родитель.- dataclass — для своих структур, Pydantic — для внешних данных.