Потому что целые числа неизменны в питоне
v.counter += 1
связывает v.counter
с новым объектом int. При повторной привязке создается атрибут экземпляра, который маскирует атрибут класса
Вы можете увидеть это, если вы посмотрите на id()
из v.counter
>>> id(v.counter)
149265780
>>> v.counter+=1
>>> id(v.counter)
149265768
Здесь вы можете видеть, что v
теперь имеет новый атрибут в __dict__
>>> v=c()
>>> v.__dict__
{}
>>> v.counter+=1
>>> v.__dict__
{'counter': 1}
Сравните случай, когда counter
является изменяемым, например, list
>>> class c:
... counter=[]
...
>>> v=c()
>>> v.counter+=[1]
>>> c.counter
[1]
>>>