🐛 Типичные ошибки

⚡ Частые ловушки

  • Присваивание через объект создаёт атрибут экземпляра, а не меняет класс.
  • Статический метод не должен принимать self.
  • __str__ должен возвращать строку, а не печатать её.
  • Изменяемые атрибуты класса разделяются между всеми объектами.
  • Добавлять атрибуты извне класса не рекомендуется.

❌ Ошибка 1: изменение атрибута класса через объект

class Book:
    library_name = "Central Library"

    def __init__(self, title):
        self.title = title


book1 = Book("1984")
book2 = Book("Brave New World")
book1.library_name = "Private Shelf"  # создаёт атрибут объекта!

print(book2.library_name)  # Central Library — не изменилось!

Почему возникает: присваивание через объект всегда создаёт или изменяет атрибут объекта, а не класса.

✅ Исправление

Book.library_name = "City Library"
print(book1.library_name)  # City Library — но у book1 остался свой атрибут!
print(book2.library_name)  # City Library

Чтобы изменить значение для всех объектов, пишите через имя класса. Если ранее объект уже получил собственный атрибут, его нужно удалить через del book1.library_name, иначе он будет затенять классовый.

❌ Ошибка 2: статический метод с параметром self

class Person:
    @staticmethod
    def greet(self):
        print("Hello!")


Person.greet()  # TypeError: greet() missing 1 required positional argument: 'self'

Сообщение об ошибке: TypeError: greet() missing 1 required positional argument: 'self'

Почему возникает: статический метод не получает self автоматически. Если параметр не нужен, его не должно быть в сигнатуре.

✅ Исправление

class Person:
    @staticmethod
    def greet() -> None:
        print("Hello!")


Person.greet()

❌ Ошибка 3: __str__ печатает вместо возврата строки

class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self):
        print(f"{self.title}")  # неправильно!


book = Book("1984")
print(book)  # None — метод ничего не возвращает

Почему возникает: __str__ должен вернуть строку. Если использовать print, метод вернёт None, и print(book) выведет None.

✅ Исправление

class Book:
    def __init__(self, title):
        self.title = title

    def __str__(self) -> str:
        return f"{self.title}"


book = Book("1984")
print(book)  # 1984

❌ Ошибка 4: изменяемый атрибут класса

class Library:
    books = []  # общий список для всех объектов!

    def add_book(self, title):
        self.books.append(title)


lib1 = Library()
lib2 = Library()
lib1.add_book("1984")
print(lib2.books)  # ['1984'] — ожидали пустой список

Почему возникает: список создаётся один раз при определении класса и разделяется между всеми экземплярами.

✅ Исправление

class Library:
    def __init__(self):
        self.books = []  # свой список для каждого объекта

    def add_book(self, title):
        self.books.append(title)


lib1 = Library()
lib2 = Library()
lib1.add_book("1984")
print(lib1.books)  # ['1984']
print(lib2.books)  # []

Изменяемые значения по умолчанию в __init__ тоже опасны: def __init__(self, books=[]) создаст один общий список. Используйте None и проверку внутри метода.

❌ Ошибка 5: добавление атрибутов извне

class Book:
    def __init__(self, title):
        self.title = title


book = Book("1984")
book.isbn = "123-456"  # атрибут появился из ниоткуда

print(book.isbn)  # работает, но код неочевиден

Почему возникает: такие атрибуты сложно отслеживать, они не видны при чтении класса и могут привести к опечаткам.

✅ Исправление

class Book:
    def __init__(self, title, isbn):
        self.title = title
        self.isbn = isbn


book = Book("1984", "123-456")
print(book.isbn)

Объявляйте все поля в __init__ или в теле класса. Если нужна гибкость, используйте @dataclass или словари.

Проверить по документации: подробнее о «позднем связывании», изменяемых значениях по умолчанию и правилах области видимости см. Python FAQ.