📜 Как показано в исходном материале
Исходный пример создаёт класс без аннотаций типов. Всё работает, но при росте проекта становится сложно отличить, какие поля общие, а какие принадлежат объекту.
class Book:
library_name = "Central Library"
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"{self.title} by {self.author}"
book = Book("1984", "George Orwell")
print(book)
print(book.library_name)
❌ Почему этот подход может быть не лучшим сейчас
- Без аннотаций типов IDE и линтеры не подскажут, какие аргументы ожидаются.
- Атрибут класса и атрибут объекта выглядят одинаково — легко перепутать.
- При изменении через объект тихо создаётся атрибут экземпляра, что сложно отловить в большом коде.
- Ручное написание
__init__,__repr__и сравнений увеличивает объём шаблонного кода.
✅ Рекомендуемый современный вариант
Современный Python позволяет явно разделить классовые и объектные поля, добавить типы и автоматизировать рутину.
from dataclasses import dataclass
from typing import ClassVar
@dataclass
class Book:
library_name: ClassVar[str] = "Central Library"
title: str
author: str
book = Book("1984", "George Orwell")
print(book) # Book(title='1984', author='George Orwell')
print(book.library_name) # Central Library
Что улучшилось:
ClassVarявно говорит, чтоlibrary_nameпринадлежит классу, а не объекту.- Аннотации типов делают интерфейс класса понятным без чтения тела методов.
@dataclassавтоматически генерирует__init__,__repr__и__eq__.- Меньше шаблонного кода — меньше ошибок.
Когда не нужен dataclass
Если класс содержит сложную логику валидации, наследование с нестандартным поведением или изменяемые значения по умолчанию, иногда удобнее оставить явный __init__ с типами.
from typing import ClassVar
class Book:
library_name: ClassVar[str] = "Central Library"
def __init__(self, title: str, author: str) -> None:
self.title = title
self.author = author
def __str__(self) -> str:
return f"{self.title} by {self.author}"
def __repr__(self) -> str:
return f"Book(title={self.title!r}, author={self.author!r})"
book = Book("1984", "George Orwell")
print(book)
🕰️ Когда старый подход ещё можно встретить
В legacy-проектах и в учебных материалах часто встречаются классы без аннотаций. Главное — распознать такой код и понимать, что obj.attr = value всегда пишет в объект, а не в класс. При рефакторинге добавляйте типы постепенно: сначала __init__, затем ClassVar для классовых полей, при необходимости — @dataclass.
@dataclass и ClassVar описаны в dataclasses и typing.ClassVar. Аннотации типов — в typing и PEP 484.