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

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

  • Изменение current_id через объект создаёт атрибут экземпляра, а не меняет класс.
  • Подсчёт возраста только через вычитание лет даёт ошибку вблизи дня рождения.
  • @classmethod и @staticmethod путают: первый получает cls, второй — ничего.
  • Изменяемый атрибут класса разделяется между всеми объектами.

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

class Student:
    current_id = 1

    def __init__(self, name):
        self.name = name
        self.student_id = Student.current_id
        Student.current_id += 1


s1 = Student("Alice")
s2 = Student("Bob")

s1.current_id = 100  # создаёт атрибут объекта, класс не меняется!
s3 = Student("Carol")

print(Student.current_id)  # 3
print(s1.current_id)       # 100 — собственный атрибут
print(s3.student_id)       # 3

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

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

Student.current_id = 100  # теперь значение изменилось в классе

❌ Ошибка 2: неправильный подсчёт возраста

from datetime import date

class Student:
    def __init__(self, name, birth_date):
        self.name = name
        self.birth_date = birth_date

    def calculate_age(self):
        today = date.today()
        return today.year - self.birth_date.year  # не учитывает месяц и день!


s = Student("Alice", date(2005, 5, 10))
print(s.calculate_age())  # может быть на 1 больше до дня рождения

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

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

def calculate_age(self):
    today = date.today()
    age = today.year - self.birth_date.year
    if (today.month, today.day) < (self.birth_date.month, self.birth_date.day):
        age -= 1
    return age

❌ Ошибка 3: путаница @classmethod и @staticmethod

class Student:
    def __init__(self, name, birth_date):
        self.name = name
        self.birth_date = birth_date

    @staticmethod
    def from_string(data):
        name, date_string = data.split(", ")
        return Student(name, date_string)  # статический метод не получает cls

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

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

class Student:
    @classmethod
    def from_string(cls, data):
        name, date_string = map(str.strip, data.split(","))
        return cls(name, date_string)

❌ Ошибка 4: мутация разделяемого списка

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

    def __init__(self, name):
        self.name = name
        Student.students.append(self)


s1 = Student("Alice")
s2 = Student("Bob")
print(len(s1.students))  # 2 — ожидали, что у каждого свой список?

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

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

class Student:
    def __init__(self, name):
        self.name = name


students = []
students.append(Student("Alice"))
students.append(Student("Bob"))

Храните коллекции объектов снаружи класса или создавайте их в __init__, если они действительно принадлежат объекту.

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