Il tuo codice non ha nulla a che fare con l'ordine di risoluzione dei metodi. La risoluzione del metodo avviene nel caso di ereditarietà multipla che non è il caso del tuo esempio. Il tuo codice è semplicemente sbagliato, perché si assume che self.__class__
è in realtà la stessa classe di quella in cui è definito il metodo e questo è sbagliato:
>>> class A(object):
... def __init__(self):
... print self.__class__
...
>>>
>>> class B(A):
... def __init__(self):
... A.__init__(self)
...
>>> B()
<class '__main__.B'>
<__main__.B object at 0x1bcfed0>
>>> A()
<class '__main__.A'>
<__main__.A object at 0x1bcff90>
>>>
in modo che quando si dovrebbe chiamare:
super(B, self).__init__(1, b, c)
sei anzi chiamando:
# super(self.__class__, self).__init__(1, b, c)
super(C, self).__init__(1, b, c)
EDIT: cercare di rispondere meglio alla domanda.
class A(object):
def __init__(self, a):
for cls in self.__class__.mro():
if cls is not object:
cls._init(self, a)
def _init(self, a):
print 'A._init'
self.a = a
class B(A):
def _init(self, a):
print 'B._init'
class C(A):
def _init(self, a):
print 'C._init'
class D(B, C):
def _init(self, a):
print 'D._init'
d = D(3)
print d.a
stampe:
D._init
B._init
C._init
A._init
3
(Una versione modificata di template pattern).
Ora i metodi dei genitori sono realmente chiamati implicitamente, ma devo essere d'accordo con Python zen dove l'esplicito è meglio di quello implicito perché il codice è meno leggibile e il guadagno è scarso. Ma attenzione che tutti i metodi _init
hanno gli stessi parametri, non è possibile dimenticare completamente i genitori e io non suggerisco di farlo.
Per l'ereditarietà singola, un approccio migliore chiama esplicitamente il metodo genitore, senza richiamare super
. In questo modo non è necessario il nome della classe corrente, ma è comunque necessario preoccuparsi di chi è la classe del genitore.
buona legge sono: how-does-pythons-super-do-the-right-thing ed i collegamenti hanno suggerito in questa domanda e nella particolarità Python's Super is nifty, but you can't use it
Se gerarchia è destinata a cambiare è sintomi di cattiva progettazione e ha conseguenze in tutte le parti che utilizzano il codice e non dovrebbe essere incoraggiato.
EDIT 2
Un altro esempio mi viene in mente, ma che utilizza metaclassi. Libreria Urwid uses metaclass per memorizzare un attributo, __super
, in classe in modo che sia necessario solo accedere a tale attributo.
Es:
>>> class MetaSuper(type):
... """adding .__super"""
... def __init__(cls, name, bases, d):
... super(MetaSuper, cls).__init__(name, bases, d)
... if hasattr(cls, "_%s__super" % name):
... raise AttributeError, "Class has same name as one of its super classes"
... setattr(cls, "_%s__super" % name, super(cls))
...
>>> class A:
... __metaclass__ = MetaSuper
... def __init__(self, a):
... self.a = a
... print 'A.__init__'
...
>>> class B(A):
... def __init__(self, a):
... print 'B.__init__'
... self.__super.__init__(a)
...
>>> b = B(42)
B.__init__
A.__init__
>>> b.a
42
>>>
cominciavo a chiedermi le firme di init e l'ereditarietà multipla –