Класс, __init__, атрибуты экземпляра и методы
Содержание курса
Инстанцирование и независимое состояние объектов
Каждый вызов класса как функции создаёт отдельный, полностью независимый объект. Напишем c1 = Counter('A') и c2 = Counter('B') — Python дважды выполнит __init__, оба раза передавая в self разный, только что созданный объект. В итоге c1 и c2 не знают друг о друге и никак не связаны.
class Counter:
def __init__(self, name):
self.name = name
self.value = 0
def increment(self, step=1):
self.value += step
def reset(self):
self.value = 0
def status(self):
return f"{self.name}: {self.value}"
c1 = Counter('A')
c2 = Counter('B')
c1.increment(3)
c1.increment()
print(c1.status()) # A: 4
print(c2.status()) # B: 0
c1.increment(3) читает c1.value, изменяет его и записывает результат обратно в c1.value. c2.value при этом остаётся нулём — у него своя копия атрибута, лежащая в совершенно другом месте памяти.
Чтобы убедиться в этом напрямую, достаточно проверить id объектов:
print(id(c1), id(c2)) # разные адреса
print(c1 is c2) # False
Оба объекта — типа Counter, оба имеют атрибуты name и value, оба понимают методы increment, reset, status. Но данные у них свои. Когда Python выполняет c2.increment(), он передаёт c2 как self — и метод работает только с c2.value.
Именно здесь проявляется разница между классом и объектом. Класс Counter — один. Он описывает структуру и поведение. Объектов Counter может быть сколько угодно, и каждый несёт своё независимое состояние.
Можно создать произвольное количество счётчиков и управлять ими независимо:
counters = [Counter(letter) for letter in 'ABC']
counters[0].increment(10)
counters[1].increment(5)
# counters[2] остаётся на 0
for c in counters:
print(c.status())
# A: 10
# B: 5
# C: 0
Каждый счётчик в списке — самостоятельный объект. Обращение к любому из них через self внутри метода гарантирует, что изменения затронут только этот конкретный экземпляр.
