Пытаясь понять oop в python, я столкнулся с этой ситуацией, которая меня озадачивает, и я не смог найти удовлетворительного объяснения... Я создавал класс Countable, у которого есть атрибут счетчика, который подсчитывает, сколько экземпляров класса имеют был инициализирован. Я хочу, чтобы этот счетчик увеличивался также при инициализации подкласса (или подподкласса) данного класса. Вот моя реализация:
class Countable(object):
counter = 0
def __new__(cls, *args, **kwargs):
cls.increment_counter()
count(cls)
return object.__new__(cls, *args, **kwargs)
@classmethod
def increment_counter(cls):
cls.counter += 1
if cls.__base__ is not object:
cls.__base__.increment_counter()
где count(cls)
для отладки, а потом запишу.
Теперь давайте создадим несколько подклассов:
class A(Countable):
def __init__(self, a='a'):
self.a = a
class B(Countable):
def __init__(self, b='b'):
self.b = b
class B2(B):
def __init__(self, b2='b2'):
self.b2 = b2
def count(cls):
print('@{:<5} Countables: {} As: {} Bs: {} B2s: {}'
''.format(cls.__name__, Countable.counter, A.counter, B.counter, B2.counter))
когда я запускаю код, подобный следующему:
a = A()
a = A()
a = A()
b = B()
b = B()
a = A()
b2 = B2()
b2 = B2()
Я получаю следующий вывод, который мне кажется странным:
@A Countables: 1 As: 1 Bs: 1 B2s: 1
@A Countables: 2 As: 2 Bs: 2 B2s: 2
@A Countables: 3 As: 3 Bs: 3 B2s: 3
@B Countables: 4 As: 3 Bs: 4 B2s: 4
@B Countables: 5 As: 3 Bs: 5 B2s: 5
@A Countables: 6 As: 4 Bs: 5 B2s: 5
@B2 Countables: 7 As: 4 Bs: 6 B2s: 6
@B2 Countables: 8 As: 4 Bs: 7 B2s: 7
Почему вначале счетчики A и B увеличиваются, несмотря на то, что я вызываю только A()
? И почему после первого вызова B()
он ведет себя так, как ожидалось?
Я уже выяснил, что для того, чтобы вести себя так, как я хочу, достаточно добавить counter = 0
в каждый подкласс, но я не смог найти объяснения, почему он так себя ведет.... Спасибо!
Я добавил несколько отладочных отпечатков и для простоты ограничил создание классов двумя. Это довольно странно:
>>> a = A()
<class '__main__.A'> incrementing
increment parent of <class '__main__.A'> as well
<class '__main__.Countable'> incrementing
@A Counters: 1 As: 1 Bs: 1 B2s: 1
>>> B.counter
1
>>> B.counter is A.counter
True
>>> b = B()
<class '__main__.B'> incrementing
increment parent of <class '__main__.B'> as well
<class '__main__.Countable'> incrementing
@B Counters: 2 As: 1 Bs: 2 B2s: 2
>>> B.counter is A.counter
False
Почему, когда B() еще не инициализирован, он указывает на ту же переменную, что и A.counter, но после создания одного объекта это другой?
B2s
всегда такой же, какBs
. - person Aran-Fey   schedule 15.09.2017__subclasses__
, который даст вам подклассы класса? stackoverflow.com/a/3862957/7432 - person Bryan Oakley   schedule 15.09.2017