Chamando o método de superclasse variável
-
27-09-2019 - |
Pergunta
Estou tentando chamar um método da superclasse usando um nome de método variável. Normalmente, eu via as duas linhas de código a seguir como equivalentes:
someObj.method()
someObj.__getattribute__( 'method' )()
E, de fato, acredito, também é isso que realmente acontece quando eu uso a primeira linha. No entanto, no exemplo a seguir, a segunda linha produz um problema estranho.
eu uso super
Para construir um super objeto e chamar o método da super classe. Fazer isso funciona diretamente como esperado, mas usando __getattribute__
Para obter o método primeiro, resulta em um loop indefinido que chama o método da subclasse repetidamente.
Veja o seguinte código:
class A:
def example ( self ):
print( 'example in A' )
class B ( A ):
def example ( self ):
print( super( B, self ).example )
print( super( B, self ).__getattribute__( 'example' ) )
super( B, self ).example()
#super( B, self ).__getattribute__( 'example' )()
print( 'example in B' )
x = B()
x.example()
Se você executar esse código, tudo funciona como esperado e você deve obter uma saída semelhante a isso:
<bound method B.example of <__main__.B object at 0x01CF6C90>>
<bound method B.example of <__main__.B object at 0x01CF6C90>>
example in A
example in B
Então, ambos os métodos, aquele com o acesso direto e o via via __getattribute__
, parece idêntico. Se você substituir a chamada do método pela linha comentada, acabará com um erro de tempo de execução de recursão.
Por que isso acontece e, mais importante, como posso realmente acessar o método da mesma maneira que o Python, quando uso a linha de trabalho?
editar
Quando pensei que já tentei de tudo, achei que isso estava funcionando:
super.__getattribute__( super( B, self ), 'example' )()
Na verdade é igual a super( B, self ).example
.
Solução
Não usar __getattribute__
Para isso: não faz o que você acha que faz. (É uma parte especializada da maquinaria do Python, principalmente para uso se você estiver implementando o novo atributo Access Magic.)
Para acesso normal ao atributo, use o getattr
/ setattr
/ delattr
Buildins:
self.example == getattr(self, 'example')
super(B, self).example == getattr(super(B, self), 'example')
(Se você quiser entender o que __getattribute__
Leia o Guia do descritor Howto e python Modelo de dados referência.)
Outras dicas
Obtendo o example
atributo de a B
objeto resulta em uma cópia encadernada de B.example
. Chamar isso resultará em um erro de recursão. Que você liga A.__getattribute__()
é irrelevante; você ainda tem um B
objeto.