Классы: первые шаги в объектно-ориентированное программирование
💻 Информатика · 10 класс
Класс объединяет данные и действия над ними: студент хранит имя и оценки и умеет считать средний балл. Разберём __init__, self, методы и простое наследование.

Зачем нужны классы
По официальному учебнику Python, класс объединяет данные и функциональность: он создаёт новый тип объектов, каждый из которых хранит своё состояние (атрибуты) и умеет выполнять действия (методы). Если словарь с оценками — это «коробка с данными», то объект — это «сотрудник», который помнит свои данные и знает, что с ними делать.
Пример 1. Класс Student
class Student:
def __init__(self, name):
if not isinstance(name, str) or not name.strip():
raise ValueError('нужна непустая строка имени')
self.name = name.strip()
self.marks = []
def add_mark(self, mark):
if type(mark) is not int or mark < 1 or mark > 5:
raise ValueError('оценка должна быть от 1 до 5')
self.marks.append(mark)
def average(self):
if not self.marks:
return None
return sum(self.marks) / len(self.marks)
anya = Student('Аня')
anya.add_mark(5)
anya.add_mark(4)
print(anya.average()) # 4.5Вызов Student('Аня') создаёт экземпляр; затем __init__ инициализирует уже созданный объект. Поэтому __init__ точнее называть инициализатором, а не операцией выделения нового объекта. Параметр self — сам создаваемый объект; через self.name и self.marks мы прикрепляем к нему данные. Внутри методов данные доступны как self.marks — поэтому average не нужен список извне. В этой модели имя должно быть непустой строкой, а оценка — целым числом от 1 до 5. Проверки отклоняют неправильные вызовы. Self — принятое имя первого параметра обычного метода экземпляра, а не отдельное ключевое слово.
Пример 2. Класс BankAccount
Учебный счёт показывает независимость состояний. В этом примере баланс и суммы — целые условные единицы; это не финансовое приложение. Проверки методов не запрещают внешнему коду напрямую присвоить self.balance другое значение: атрибут остаётся публичным.
class BankAccount:
def __init__(self, owner, balance=0):
if balance < 0:
raise ValueError('баланс не может быть отрицательным')
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError('вклад должен быть положительным')
self.balance += amount
def withdraw(self, amount):
if amount <= 0:
raise ValueError('сумма снятия должна быть положительной')
if amount > self.balance:
raise ValueError('недостаточно средств')
self.balance -= amountСоздадим два счёта: a = BankAccount('Аня', 100), b = BankAccount('Борис', 50). Снятие со счёта a меняет только a.balance: b остаётся равен 50. Здесь self.balance относится к конкретному экземпляру. Список self.marks создаётся заново в каждом __init__, поэтому оценки разных учеников тоже независимы. Если вынести marks = [] в тело класса, список станет общим атрибутом класса, и изменения будут неожиданно видны нескольким ученикам. Неудачные операции (снять 0, -5 или 21 при балансе 20) отклоняются исключением и не меняют состояние.
Наследование: класс-наследник
Наследник использует поведение базового класса и может добавлять или переопределять методы. Вызов super помогает выполнить базовую инициализацию. Диапазон возраста 6–19 ниже — условие учебной модели, а не общее правило поступления в школу.
class AgedStudent(Student):
def __init__(self, name, age):
if type(age) is not int or age < 6 or age > 19:
raise ValueError('возраст школьника: от 6 до 19')
super().__init__(name)
self.age = age
def is_at_least_15(self):
return self.age >= 15Вызов super().__init__(name) делегирует инициализацию базовому классу — проверки имени не дублируются. AgedStudent('Дарья', 16) умеет всё, что Student: add_mark и average работают без изменений, а метод is_at_least_15 добавлен только наследнику.
Проверь себя
- Что выведет print(anya.average()), если оценок не добавляли? Ответ: None — метод average так написан, что безопасен для пустого списка.
- Зачем методам первый параметр self? Ответ: через него метод получает объект, у которого вызван, и читает его атрибуты.
- Что произойдёт при Student('')? Ответ: ValueError — __init__ поднимает исключение: вызов класса не возвращает успешно инициализированный экземпляр. Само выделение объекта происходит раньше инициализации.
- AgedStudent('Ева', 10).is_at_least_15()? Ответ: False — 10 меньше 15; при этом add_mark(5) всё равно работает, метод унаследован.
Кратко о главном
Класс — шаблон объектов с данными (атрибуты) и действиями (методы). __init__ готовит объект, при обычном вызове метода экземпляр передаётся первым аргументом self; наследование позволяет использовать и переопределять поведение базы. Проверяйте данные через raise ValueError — плохие объекты не должны создаваться.