Próbuję zrozumieć oop w pytonie Przyszedłem do tej sytuacji, która mnie zastanawia i nie byłem w stanie znaleźć satysfakcjonującego wyjaśnienia ... Budowałem klasę Countable, która ma licznik atrybut, który zlicza liczbę instancji klasy, które zostały zainicjalizowane. Chcę, aby ten licznik był zwiększany również wtedy, gdy inicjowana jest podklasa (lub subklasę) danej klasy. Oto moja realizacja:Dziedziczenie zmiennych klasowych w pytonie
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()
gdzie count(cls)
jest tam dla celów debugowania, a później napisać go w dół.
Teraz zróbmy kilka podklas to:
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))
kiedy uruchomić kod jak poniżej:
a = A()
a = A()
a = A()
b = B()
b = B()
a = A()
b2 = B2()
b2 = B2()
I uzyskać następujący wynik, który wygląda dziwnie do mnie:
@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
Dlaczego na początku licznik A i B zwiększa się, pomimo tego, że dzwonię pod numer A()
? I dlaczego po raz pierwszy dzwonię pod numer B()
, który zachowuje się jak oczekiwano?
Już się dowiedziałem, że zachowanie takie, jak chcę, wystarczy dodać counter = 0
dla każdej podklasy, ale nie byłem w stanie znaleźć wyjaśnienia, dlaczego zachowuje się w ten sposób .... Dziękuję!
Dodałem kilka odbitek do debugowania, a dla uproszczonego, ograniczonego tworzenia klas do dwóch. Jest to dość dziwne:
>>> 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
Jak to się stało, gdy B() nie jest jeszcze zainicjowany, to wskazuje na tej samej zmiennej jako A.counter ale po utworzeniu pojedynczy obiekt jest inna?
I nie można odtworzyć swoje wyjście. Moje wyjście dla 'B2s' jest zawsze takie samo jak' Bs'. –
Edytowałem Twoje pytanie z uproszczonym przykładem problemu. To interesujące pytanie, mam nadzieję, że ktoś może rzucić nieco światła na proces. – Vinny
@Przypomnienie, że masz rację, wkleiłem dane wyjściowe innego przykładu ... teraz to naprawiam! –