Codebra
29 января 2026 в 18:34

Урок 64. Основы написания классов в Python

В этом уроке на основе простых примеров будем разбираться более детально с оператором class и его преимуществами.
📝

Внимание! На этой странице вы найдете материал урока из архивного курса по Python. Курс был написан в 2024 году и по-прежнему актуален для начинающих разработчиков.

Теоретический материал сохранен в исходном виде, а практические задания с автоматической проверкой вынесены в отдельные интенсивы и задания.

Полный список уроков доступен по тегу Архивный курс по Python и на странице первого урока.

📝 Кратко
  • В этом уроке мы разберемся с оператором class и его преимуществами на основе простых примеров.
  • Объект класса - это "фабрика" для производства экземпляров.
  • Перегрузка операторов позволяет изменить поведение оператора в зависимости от типа объекта.
  • Наследование классов - это поиск атрибутов среди связанных объектов.
  • Атрибуты объекта реализуются как словари, связанные с другими словарями.
  • Каждый экземпляр имеет ссылку на свой класс и кортеж ссылок из суперклассов.
  • Динамическое создание атрибута для класса возможно.

Введение

В предыдущем уроке мы поверхностно пробежались по основным отличительным особенностям классов от ранее изучаемых средств. В этом уроке на основе простых примеров будем разбираться более детально с оператором class и его преимуществами.

Объект класса или экземпляров? Под объектом класса понимается сама «фабрика» для производства экземпляров. Вспомним класс Wheel из предыдущего урока:

class Wheel:
    pressure = 2.0

    def forward_rotation(self):
        pass

    def backwards_rotation(self):
        pass

И его использование:

fl = Wheel()

Выполнение оператора class создает объект класса и присваивает ему имя Wheel, который мы в дальнейшем используем в роли «фабрики» для экземпляров.

Объект fl является экземпляром. Таких экземпляров может быть бесчисленное множество.

Перегрузка операторов

В предыдущем уроке мы упоминали про перегрузку операторов, когда разбирались с конструктором класса. Создадим простой класс, в котором будет определен конструктор для инициализации атрибута data.

class SimpleSum:
    data = 0

    def __init__(self, d):
        self.data = d

num = SimpleSum(10)

print(num.data) # => 10
print(num + 10) # => ???

Мы создали экземпляр num, и вывели значение атрибута data. Но что произойдет, если мы попробуем прибавить к num число 10? Будет поднято исключение TypeError (про исключения мы говорили в уроке «Обработка исключений (try/except) в Python»).

Оператор «+» можно перегрузить точно также, как и конструктор класса __init__. Метод __add__ будет выполнятся, если экземпляр класса SimpleSum будет встречен в выражении +.

class SimpleSum:
    data = 0

    def __init__(self, d):
        self.data = d

    def __add__(self, second):
        self.data = self.data + second

num = SimpleSum(10)

print(num.data) # => 10
num + 10
print(num.data) # => 20

Таким образом, мы перегрузили оператор «+» и теперь Python понимает, что не нужно пытаться прибавить к объекту класса SimpleSum простое число, а следует прибавить к атрибуту data, этого экземпляра и сохранить результат в нем же. К перегрузке операторов мы еще вернемся.

Другие атрибуты класса и снова про наследование

Модель наследования очень проста, она сводится к поиску атрибутов среди связанных объектов. Давайте создадим пустой класс:

class Empty:
    pass

С оператором pass вы знакомы из урока «Урок 35. Операторы break, continue и pass в Python». С большим успехом мы можем присоединить к нему новые атрибуты, например:

Empty.name = "Иван"
print(Empty.name)

Теперь посмотрим на модель наследования в действии. Создадим два экземпляра из объекта Empty.

Empty.name = "Иван"

x = Empty()
y = Empty()

print(x.name) # => Иван
print(y.name) # => Иван

Фактически, экземпляры не имеют атрибутов – они берут их из объекта класса. В следующем примере экземпляр x по-прежнему наследует атрибут name, но мы присвоили ему другое значение:

x.name = "Петр"

print(x.name) # => Петр
print(y.name) # => Иван

Как мы будем говорить в дальнейшем, атрибуты объекта реализуются как словари, которые связаны с другими словарями:

Empty.__dict__.keys() # => dict_keys(['__module__', '__dict__', '__weakref__', '__doc__', 'name'])

x.__dict__.keys() # => dict_keys(['name'])

Возвращаясь к поиску в иерархии наследования, каждый экземпляр имеет ссылку на свой класс, которую можно получить следующим образом:

x.__class__ # => <class '__main__.Empty'>

Также можно получить кортеж ссылок из суперклассов для объекта, например:

print(Empty.__bases__) # => (<class 'object'>,)

Наш класс Empty наследуется только от общего суперкласса object, являющимся родителем для всех и о котором будем говорить в дальнейшем.

Ранее было показано, как динамически создать атрибут для класса. Теперь попробуем добавить метод в наш пустой класс Empty. Напомню про отличие функции от метода класса, в последнем есть ссылка на сам объект (self). Учтем это при написании функции:

def print_name(obj):
    print(obj.name)

Empty.name = "Иван"

print_name(Empty) # => Иван

Теперь сделаем функцию print_name() методом класса Empty с именем method_print().

Empty.name = "Иван"
Empty.method_print = print_name

x = Empty()

x.method_print() # => Иван

В этом уроке мы разграничили понятия экземпляр и объект класса, немного углубились в перегрузку операторов и начали вникать в наследование классов. Конечно, о многом не было сказано и какие-то вещи остались в тени, но вы не беспокойтесь, в последующих уроках мы будем раскладывать все по полочкам и углубляться в каждую тему. В следующем уроке познакомимся с написание конструктора класса, узнаем о инкапсуляции и поработаем с базой данных (вернее, с ее аналогом на основе текстового файла).

📝

Переходите к следующему уроку курса, а так же не забудьте посмотреть новый материал на Codebra по тегу Python.