Объяснение к уроку
После этого урока ты сможешь:
__init__.Атрибут экземпляра сохраняется на одном объекте, обычно присваиваясь в __init__ как self.name = name. Атрибут класса объявляется в теле класса и разделяется как значение по умолчанию всеми экземплярами этого класса:
class Worker:
region = "eu"
def __init__(self, name):
self.name = nameВыражение Worker.region читает настройку класса. Выражение worker.region также читает ее, пока этот конкретный объект не получит собственный атрибут region. Если присвоить worker.region = "us", этот объект перекроет настройку класса; другие воркеры затронуты не будут.
Для действительно общей конфигурации обновляй Worker.region (класс), а не один экземпляр. Для состояния конкретного объекта, такого как имя воркера, счетчик повторов или история событий, используй self.attribute внутри __init__.
Важная ловушка с изменяемым состоянием: список, определенный в теле класса, будет общим для всех экземпляров. Если каждому экземпляру нужен собственный список, создавай self.events = [] в конструкторе.
class ApiClient:
scheme = "https"
def __init__(self, service):
self.service = service
first = ApiClient("users")
second = ApiClient("billing")
print(f"{first.service}: {first.scheme}")
print(f"{second.service}: {second.scheme}")Вывод:
users: https
billing: httpsОба объекта читают одну и ту же настройку класса, сохраняя собственные имена сервисов.
class Job:
mode = "safe"
first = Job()
second = Job()
Job.mode = "fast"
print(first.mode)
print(second.mode)Вывод:
fast
fastНи один экземпляр не определяет собственное поле mode, поэтому оба по-прежнему читают атрибут класса.
class Storage:
tier = "standard"
primary = Storage()
backup = Storage()
primary.tier = "premium"
print(primary.tier)
print(backup.tier)
print(Storage.tier)Вывод:
premium
standard
standardprimary.tier стал атрибутом экземпляра; общее значение класса по умолчанию осталось неизменным.
class Monitor:
def __init__(self, name):
self.name = name
self.events = []
def record(self, event):
self.events.append(event)
api = Monitor("api")
queue = Monitor("queue")
api.record("started")
print(api.events)
print(queue.events)Вывод:
['started']
[]Каждый вызов конструктора создает свежий список для своего монитора.
| Ситуация | Где присваивать |
|---|---|
| Общее значение по умолчанию или настройка | В теле класса: mode = "safe" |
| Изменить общую настройку | Worker.mode = "fast" |
| Состояние конкретного объекта | В __init__: self.name = name |
| Переопределить общее значение для одного экземпляра | worker.mode = "custom" |
| Изменяемый список отдельного объекта | В __init__: self.events = [] |
obj.setting = value не меняет ClassName.setting; это создает или обновляет атрибут экземпляра.self.name в теле класса — это не то, как работает инициализация экземпляров; используй __init__.