Como o `super` interage com o atributo` __mro__` de uma classe na herança múltipla?
Hoje eu li odoc oficial de super.
Na qual mencionou herança múltipla, será decidido pelo__mro__
atributo de uma classe.
Então fiz um pouco de experiência, mas seu resultado me surpreendeu.
# CODE PART
class GrandFather(object):
def p(self):
print "I'm old."
class Father(GrandFather):
def p(self):
print "I'm male."
class Mother(object):
def p(self):
print "I'm female."
class Son(Father, Mother):
def p(self):
print "busy, busy, crwaling. "
# EXPERIMENT PART
In [1]: Son.__mro__
Out[1]: (__main__.Son, __main__.Father, __main__.GrandFather, __main__.Mother, object)
In [2]: Father.__mro__
Out[2]: (__main__.Father, __main__.GrandFather, object)
In [3]: Mother.__mro__
Out[3]: (__main__.Mother, object)
In [4]: GrandFather.__mro__
Out[4]: (__main__.GrandFather, object)
In [5]: s = Son()
In [6]: super(Son, s).p()
I'm male.
In [7]: super(Father, s).p()
I'm old.
In [8]: super(Mother, s).p()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-ce4d0d6ef62d> in <module>()
----> 1 super(Mother, s).p()
AttributeError: 'super' object has no attribute 'p'
In [9]: super(GrandFather, s).p()
I'm female.
Abaixo faz parte do documento oficial que mencionei acima, que diz:
super(type[, object-or-type])
Return a proxy object that delegates method calls to a parent or sibling class of type.
This is useful for accessing inherited methods that have been overridden in a class.
The search order is same as that used by getattr() except that the type itself is skipped.
The __mro__ attribute of the type lists the method resolution search order
used by both getattr() and super().
The attribute is dynamic and can change whenever the inheritance hierarchy is updated.
If the second argument is an object, isinstance(obj, type) must be true.
Combinando este documento e o resultado do meu experimento. A parte mais confusa é que ao ligar comsuper(GrandFather, s).p()
chama op()
doMother
, masMother
não está emGrandFather
é__mro__
, e está em uma ordem muito inferior deSon
é__mro__
.
Depois de refletir um pouco. Eu recebi uma explicação plausível que indica a incompletude ou deficiência do documento oficial:
Ou seja, ao usar comsuper(type, instance)
, asuper
A função procurará no__mro__
atributo doclass
de quem é seuinstance
é build, mas não o__mro__
atributo dotype
você passou parasuper
, mesmo que satisfizesse aisinstance(instance, type)
condição.
Então, o que aconteceu quando você digitousuper(Class, instance)
é:
isinstance(instance, Class)
é verdade.Python encontre o__class__
atributo deinstance
,pegue o
instance.__class__
é__mro__
atributo.Python encontre o índice deClass
você passou parasuper
no__mro__
tupla na etapa 2.Python adicione o índice da etapa 3 por 1, use-o para obter a classe correspondente em__mro__
tupla da etapa 2 e retorne o super delegado dessa classe correspondente.Se o índice na etapa 4 exceder o comprimento de__mro__
do passo 2, o delegado da última aula__mro__
da etapa 2 é retornado, que é oobject
classe.Meu entendimento está correto?
Se eu estiver errado, qual é o mecanismo correto quesuper
interage comtype
é__mro__
?
Se eu estiver certo, como devo levantar um problema para a modificação oficial de documentos em python?
Porque acho que a versão atual sobre esse item pode ser enganosa.
PS: Este teste foi feito porPython 2.7.6 within IPython 3.2.1
.