Su código no tiene nada que ver con la orden de resolución de métodos. La resolución del método se produce en el caso de la herencia múltiple, que no es el caso de su ejemplo. Su código es simplemente errónea porque se supone que self.__class__
es en realidad la misma clase de aquel en el que se define el método y esto está mal:
>>> 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>
>>>
lo que cuando se debe llamar:
super(B, self).__init__(1, b, c)
estás de hecho llamar:
# super(self.__class__, self).__init__(1, b, c)
super(C, self).__init__(1, b, c)
EDITAR: tratando de responder mejor a la pregunta.
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
grabados:
D._init
B._init
C._init
A._init
3
(Una versión modificada de template pattern).
Ahora los métodos de los padres realmente se llaman implícitamente, pero tengo que estar de acuerdo con python zen donde explícito es mejor que implícito porque el código es menos legible y la ganancia es pobre. Pero tenga en cuenta que todos los métodos _init
tienen los mismos parámetros, no puede olvidar por completo a los padres y no sugiero que lo haga.
Para la herencia simple, un mejor enfoque es llamar explícitamente al método principal, sin invocar super
. De este modo, no es necesario que nombre la clase actual, pero igual debe importar quién es la clase principal.
buenas lecturas son: how-does-pythons-super-do-the-right-thing y los enlaces sugieren en esa pregunta y en particularidad Python's Super is nifty, but you can't use it
Si jerarquía es probable que cambie es síntomas de un mal diseño y tiene consecuencias en todas las partes que están utilizando ese código y no debe Ser alentado.
EDIT 2
Otro ejemplo que me viene a la mente, pero que utiliza metaclases. Biblioteca Urwid uses metaclass para almacenar un atributo, __super
, en la clase, de modo que solo necesita acceder a ese atributo.
Ex:
>>> 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
>>>
empecé a preguntarme sobre las firmas init y la herencia múltiple –