Python super ignorar MRO
-
21-12-2019 - |
Pergunta
Eu tenho um herdado de uma classe e sobrescrever um método que também é herdado de uma classe base.Mas a coisa é que o meio, o método cria uma exceção que eu gostaria de ignorar chamando o primeiro método declarado.Existe uma maneira de especificar para o mro que ignora a segunda chama?
Um exemplo poderia ser:
class Base(object):
def __init__(self):
res = "Want this"
print res
class BaseA(Base):
def __init__(self):
res = super(BaseA, self).__init__()
res = "Not this"
print res
class BaseB(BaseA):
def __init__(self):
res = super(BaseB, self).__init()
#At this poing res is "Not this"
#The desire is that it would be "Want this"
print res
Muito obrigado
PD:Algo como classe BaseB(Base, BaseA) poderia trabalhar?
Solução
Normalmente você gostaria de corrigir esse método em vez disso.
No entanto, o primeiro argumento para super()
é o lugar para começar a procurar o método seguinte a partir de.Normalmente, seria a classe atual, mas você também pode passar na classe base:
class BaseB(BaseA):
def __init__(self):
res = super(BaseA, self).__init__()
Aqui, super()
leva a MRO de type(self)
, encontra BaseA
no que MRO, e olha para a próxima classe de execução __init__
.
Outra maneira de ignorar a problemática __init__
o método é apenas para chamar independente do método de Base
diretamente:
class BaseB(BaseA):
def __init__(self):
res = Base.__init__(self)
ignorando qualquer MRO pesquisas inteiramente.
Outras dicas
O Caminho Certo para corrigir esse problema é criar uma nova hierarquia de classes que substitui o método incorreto com uma melhor implementação.Se você insistir em hackery porém, isso pode ser o que você deseja:
class BaseB(BaseA):
def __init__(self):
res = super(BaseA, self).__init()
#At this poing res is "Not this"
#The desire is that it would be "Want this"
print res
Note que estou pedindo para o super implementação com relação ao BaseA, o que significa que o BaseA implementação nunca é usado.
No entanto, este pode fazer a Coisa Errada quando diamante herança está envolvido.Considere:
class Base(object):
def __init__(self):
print 'initing Base'
class BaseA(Base):
def __init__(self):
print 'initing BaseA'
res = super(BaseA, self).__init__()
class BaseB(BaseA):
def __init__(self):
print 'initing BaseB'
res = super(BaseA, self).__init__()
class BaseC(BaseA):
def __init__(self):
print 'initing BaseC'
res = super(BaseC, self).__init__()
class BaseD(BaseB, BaseC):
def __init__(self):
print 'initing BaseD'
res = super(BaseD, self).__init__()
print BaseD()
A saída é :
initing BaseD
initing BaseB
initing Base
<__main__.BaseD object at 0x7f1e693a0110>
BaseC
foi ignorado, apesar de que não é o que queríamos.Isso é porque BaseC
veio entre BaseB
e BaseA
no método de resolução de ordem, por isso, quando deixamos de lado a partir de BaseB
para BaseA
inadvertidamente, negligenciadas BaseC
.
>>> print [cls.__name__ for cls in BaseD.mro()]
['BaseD', 'BaseB', 'BaseC', 'BaseA', 'Base', 'object']
Como bout apenas
Base.__init__(self)