В предыдущем уроке мы научились создавать методы класса и разобрали важный параметр self, который позволяет методу работать с конкретным объектом.
Теперь пришло время познакомиться с двумя особыми методами Python, которые играют ключевую роль в жизненном цикле объекта:
__init__()— инициализация объекта__del__()— финализация объекта
Эти методы относятся к так называемым магическим методам.
В Python существует набор специальных методов, которые автоматически вызываются интерпретатором в определённых ситуациях.
Такие методы принято называть магическими.
Их легко узнать по форме записи:
__имя_метода__
Например:
__init__
__del__
__str__
__repr__
__add__
Особенность этих методов:
- они не вызываются напрямую
- Python вызывает их автоматически
В этом уроке мы разберём два из них.
| Метод | Назначение |
|---|---|
__init__ |
инициализация объекта |
__del__ |
финализация (удаление объекта) |
Возьмём класс Point из прошлого урока.
class Point:
color = "red"
circle = 2
def set_coords(self, x, y):
self.x = x
self.y = y
def get_coords(self):
return (self.x, self.y)Создадим объект.
pt = Point()Проблема в том, что у объекта нет координат.
Если попытаться получить координаты:
pt.get_coords()мы получим ошибку.
AttributeError: 'Point' object has no attribute 'x'
Почему?
Потому что координаты создаются только после вызова метода:
pt.set_coords(1, 2)Это неудобно.
Логичнее, если объект сразу создаётся с нужными данными.
Именно для этого используется метод __init__.
Метод __init__ автоматически вызывается сразу после создания объекта.
Добавим его в класс.
class Point:
color = "red"
circle = 2
def __init__(self):
print("Вызов метода __init__")
self.x = 0
self.y = 0Теперь создадим объект.
pt = Point()Вывод:
Вызов метода __init__
Посмотрим атрибуты объекта.
print(pt.__dict__)Результат:
{'x': 0, 'y': 0}
Что произошло?
Метод __init__ автоматически создал атрибуты x и y.
Создание объекта происходит в несколько этапов.
Схема выглядит так:
Point()
│
│
▼
1. Выделение памяти для объекта
│
▼
2. Вызов метода __new__
│
▼
3. Создание объекта
│
▼
4. Вызов метода __init__
│
▼
5. Объект готов к использованию
Метод __new__ отвечает за создание объекта,
а __init__ — за настройку уже созданного объекта.
Метод __new__ мы подробно разберём на следующем уроке.
Чаще всего __init__ принимает аргументы.
Например:
class Point:
def __init__(self, x, y):
self.x = x
self.y = yТеперь при создании объекта нужно передать координаты.
pt = Point(1, 2)Внутри метода происходит следующее:
self.x = 1
self.y = 2
Теперь объект содержит координаты.
print(pt.__dict__)Результат:
{'x': 1, 'y': 2}
Разберём внимательно строку:
self.x = xЗдесь происходит две вещи:
-
создаётся атрибут объекта
x -
в него записывается значение аргумента
То есть self — это ссылка на конкретный объект.
Иногда можно запутаться в этой записи.
Например:
def __init__(self, a, b):
self.x = a
self.y = bЭто абсолютно корректно.
Параметры функции могут называться как угодно.
Но хорошей практикой считается:
имя параметра = имя атрибута
Поэтому чаще пишут так:
def __init__(self, x, y):
self.x = x
self.y = yЭто делает код более читаемым.
Поскольку __init__ — это обычная функция,
в ней можно использовать значения по умолчанию.
class Point:
def __init__(self, x=0, y=0):
self.x = x
self.y = yТеперь возможны разные варианты создания объекта.
pt1 = Point()
pt2 = Point(10)
pt3 = Point(10, 20)Результат:
pt1 → (0,0)
pt2 → (10,0)
pt3 → (10,20)
Создадим класс пользователя.
class User:
def __init__(self, name, age):
# имя пользователя
self.name = name
# возраст пользователя
self.age = age
def show_info(self):
print("Имя:", self.name)
print("Возраст:", self.age)Создание объекта:
user = User("Иван", 25)
user.show_info()Вывод:
Имя: Иван
Возраст: 25
Теперь перейдём ко второму методу.
__del__(self)
Он вызывается перед уничтожением объекта.
Добавим его в класс.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __del__(self):
print("Удаление объекта:", self)Создадим объект.
pt = Point(1, 2)Когда программа завершится, можно увидеть сообщение:
Удаление объекта: <__main__.Point object ...>
Это означает, что объект был уничтожен.
Python использует сборщик мусора (Garbage Collector).
Основная идея очень простая:
объект существует пока на него есть ссылки.
Схема:
pt ───► объект Point
Если удалить ссылку:
del ptто объект становится ненужным.
И Python может удалить его из памяти.
Перед удалением вызывается __del__.
class Test:
def __init__(self):
print("Объект создан")
def __del__(self):
print("Объект удалён")
t = Test()
del tВывод:
Объект создан
Объект удалён
Метод __del__ используется очень редко.
Причины:
Python может удалить объект не сразу.
Особенно если работает сборщик мусора.
Если программа завершается аварийно.
Например при циклических ссылках.
Поэтому в реальных проектах __del__ почти не используют.
Гораздо чаще применяются:
- контекстные менеджеры (
with) - методы закрытия ресурсов (
close())
Иногда __del__ используют для:
- логирования удаления объекта
- отладки
- освобождения ресурсов
Пример:
class FileLogger:
def __init__(self, filename):
self.filename = filename
print("Открыт файл:", filename)
def __del__(self):
print("Закрытие файла:", self.filename)Но даже в таких случаях чаще используют контекстные менеджеры.
В этом уроке мы разобрали два важных магических метода.
Используется для инициализации объекта.
Он:
- вызывается автоматически
- создаёт атрибуты объекта
- принимает аргументы
Вызывается перед уничтожением объекта.
Но используется очень редко, потому что:
- момент вызова трудно предсказать
- сборщик мусора работает автоматически
- Что такое магические методы?
- Когда вызывается метод
__init__? - Что обычно происходит внутри
__init__? - Почему
selfобязательно используется в__init__? - Можно ли передавать параметры в
__init__? - Что происходит если не передать аргументы в
__init__, когда они обязательны? - Когда вызывается метод
__del__? - Почему
__del__редко используется в реальных проектах? - Что такое сборщик мусора Python?
- Сколько этапов происходит при создании объекта?
Объявите класс Money так, чтобы объекты этого класса можно было создавать следующим образом:
my_money = Money(100)
your_money = Money(1000)
Число, передаваемое при создании объекта, должно сохраняться в локальном атрибуте объекта money.
После создания объектов выведите значения денег:
print(my_money.money)
print(your_money.money)
Ожидаемый вывод:
100
1000
Объявите класс Point так, чтобы объекты можно было создавать командами:
p1 = Point(10, 20)
p2 = Point(12, 5, 'red')
Аргументы:
x — координата
y — координата
color — цвет точки
Если цвет не указан, он должен автоматически принимать значение:
black
Создайте 1000 объектов этого класса со следующими координатами:
(1,1), (3,3), (5,5), (7,7) ...
Каждая следующая точка должна увеличиваться на 2.
Все объекты нужно сохранить в список:
points
Для второго объекта списка задайте цвет "yellow".
Объявите три класса:
Line
Rect
Ellipse
Объекты этих классов должны создаваться следующим образом:
g1 = Line(a, b, c, d)
g2 = Rect(a, b, c, d)
g3 = Ellipse(a, b, c, d)
Передаваемые параметры:
a, b — координаты первой точки
c, d — координаты второй точки
В каждом объекте нужно создать атрибуты:
sp = (a, b)
ep = (c, d)
Создайте 213 объектов случайных классов:
Line
Rect
Ellipse
Координаты также должны генерироваться случайно в диапазоне от 0 до 100.
Все объекты сохраните в список:
elements
После этого обнулите координаты только у объектов класса Line.
Создайте класс User.
При создании объекта должны задаваться:
name
В конструкторе (__init__) должно выводиться сообщение:
Пользователь <name> создан
В финализаторе (__del__) должно выводиться сообщение:
Пользователь <name> удалён
Затем:
- Создайте список
users - Добавьте в него 3 объекта
User - Удалите один объект из списка
- Принудительно удалите переменную
Объявите класс TriangleChecker.
Объекты должны создаваться так:
tr = TriangleChecker(a, b, c)
Где:
a, b, c — длины сторон треугольника
В классе должен быть метод:
is_triangle()
Метод должен возвращать:
1 — если хотя бы одна сторона не число
или меньше либо равна нулю
2 — если такие стороны не могут образовать треугольник
3 — если стороны образуют треугольник
Проверки выполняются строго в указанном порядке.
Затем прочитайте значения:
a, b, c = map(int, input().split())
Создайте объект tr и выведите результат метода is_triangle().
Создайте три класса:
- CPU
- Memory
- MotherBoard
Объекты создаются следующим образом:
cpu = CPU(name, frequency)
mem = Memory(name, volume)
mb = MotherBoard(name, cpu, mem1, mem2, ...)
Каждый объект должен хранить:
CPU
name
fr
Memory
name
volume
MotherBoard
name
cpu
mem_slots
total_mem_slots = 4
Список mem_slots должен содержать не более 4 объектов Memory. Если при создании передать большее количество оперативной памяти, то mem_slots должен будет содержать только первые 4 из них.
Класс MotherBoard должен иметь метод get_config() который возвращает список строк:
Материнская плата: <name>
Центральный процессор: <cpu_name>, <frequency>
Слотов памяти: 4
Память: name1 - volume1; name2 - volume2
Создайте материнскую плату с 1 CPU и 2 планками памяти
Выведите результат get_info() на экран.
Создайте материнскую плату с 1 CPU и 5 планками памяти.
Выведите результат get_info() на экран.
В программировании часто используются специальные структуры данных для хранения и обработки информации. Одна из самых базовых структур — связный список.
Односвязный список (Singly Linked List) — это последовательность объектов, где каждый объект хранит:
- данные
- ссылку на следующий объект
В отличие от обычного списка Python (list), элементы связного списка не хранятся в одной структуре.
Каждый элемент существует как отдельный объект, который знает только о следующем элементе.
Схематично это выглядит так:
head_obj
|
v
+---------+ +---------+ +---------+ +---------+
| data | ---> | data | ---> | data | ---> | data |
| next_obj| | next_obj| | next_obj| | next_obj|
+---------+ +---------+ +---------+ +---------+
| | | |
v v v v
объект2 объект3 объект4 None
- Первый объект называется головой списка (head).
- Каждый объект хранит ссылку на следующий объект.
- Последний элемент содержит
next_obj = None.
Условие Задачи:
Объявите в программе класс ListObject, объекты которого создаются командой:
obj = ListObject(data)где
data — строка, которая должна сохраняться внутри объекта.
Каждый объект класса ListObject должен иметь два локальных атрибута:
1. data
строка, переданная при создании объекта.
2. next_obj
ссылка на следующий объект списка.
Если следующий объект отсутствует, значение должно быть:
NoneВ классе ListObject необходимо реализовать метод:
link(self, obj)
Назначение метода:
соединить текущий объект self со следующим объектом obj.
После вызова метода:
self.next_obj → obj
Далее в программе необходимо сформировать односвязный список используя строки из следующего списка:
lst_in = [
'Введение в ООП',
'1 Концепция ООП простыми словами',
'2 Классы и объекты. Атрибуты классов и объектов',
'3 Методы класса и параметр `self`',
'4 Инициализатор init и финализатор del'
]Ваша задача:
- Для каждой строки необходимо создать объект класса
ListObject. - В атрибуте
dataкаждого объекта должна храниться соответствующая строка. - Все объекты должны быть последовательно соединены друг с другом через метод
link(). - Переменная
head_objдолжна ссылаться на первый объект списка.