Estou tentando entender a diferença entre __getattr__
e __getattribute__
, no entanto, estou falhando nisso.
A resposta para a pergunta Stack Overflow Diferença entre __getattr__
vs__getattribute__
diz:
__getattribute__
é invocado antes de examinar os atributos reais no objeto e, portanto, pode ser difícil de implementar corretamente. Você pode terminar em recursões infinitas com muita facilidade.
Não tenho absolutamente nenhuma idéia do que isso significa.
Então continua dizendo:
Você quase certamente quer
__getattr__
.
Por quê?
Eu li que se __getattribute__
falhar, __getattr__
é chamado. Então, por que existem dois métodos diferentes fazendo a mesma coisa? Se meu código implementa as novas classes de estilo, o que devo usar?
Estou procurando alguns exemplos de código para esclarecer esta questão. Eu pesquisei no Google da melhor maneira possível, mas as respostas que encontrei não discutem o problema completamente.
Se houver alguma documentação, estou pronto para ler isso.
fonte
Respostas:
Alguns princípios básicos primeiro.
Com objetos, você precisa lidar com seus atributos. Normalmente fazemos
instance.attribute
. Às vezes, precisamos de mais controle (quando não sabemos o nome do atributo com antecedência).Por exemplo,
instance.attribute
se tornariagetattr(instance, attribute_name)
. Usando esse modelo, podemos obter o atributo fornecendo o attribute_name como uma string.Uso de
__getattr__
Você também pode dizer a uma classe como lidar com atributos que ela não gerencia explicitamente e fazer isso por meio do
__getattr__
métodoO Python chamará esse método sempre que você solicitar um atributo que ainda não tenha sido definido, para que você possa definir o que fazer com ele.
Um caso de uso clássico:
Advertências e uso de
__getattribute__
Se você precisar capturar todos os atributos, independentemente de existirem ou não , use-o
__getattribute__
. A diferença é que__getattr__
apenas é chamado para atributos que realmente não existem. Se você definir um atributo diretamente, a referência a esse atributo o recuperará sem chamar__getattr__
.__getattribute__
é chamado o tempo todo.fonte
getattr(instance, attribute_name)
.". Não deveria ser__getattribute__(instance, attribute_name)
?getattr
é uma função interna .getattr(foo, 'bar')
é equivalente afoo.bar
.__getattr__
só é chamado se estiver definido, como não é herdada deobject
__getattribute__
é chamado sempre que ocorre um acesso ao atributo.Isso causará uma recursão infinita. O culpado aqui é a linha
return self.__dict__[attr]
. Vamos fingir (está perto o suficiente da verdade) que todos os atributos estão armazenadosself.__dict__
e disponíveis pelo nome. A linhatenta acessar o
a
atributo def
. Isso chamaf.__getattribute__('a')
.__getattribute__
então tenta carregarself.__dict__
.__dict__
é um atributo deself == f
chamadas python,f.__getattribute__('__dict__')
que tenta novamente acessar o atributo'__dict__
'. Isso é recursão infinita.Se
__getattr__
tivesse sido usado em vez disso,f
possui uma
atributo.f.b
), não teria sido chamado para localizar__dict__
porque já está lá e__getattr__
será invocado apenas se todos os outros métodos de localização do atributo falharem .A maneira 'correta' de escrever a classe acima usando
__getattribute__
ésuper(Foo, self).__getattribute__(attr)
vincula o__getattribute__
método da superclasse 'mais próxima' (formalmente, a próxima classe no MRO da ordem de resolução de classe) ao objeto atualself
e, em seguida, o chama e deixa que faça o trabalho.Todo esse problema é evitado usando o
__getattr__
que permite que o Python faça suas coisas normais até que um atributo não seja encontrado. Nesse ponto, o Python__getattr__
passa o controle para o seu método e permite que ele crie alguma coisa.Também é importante notar que você pode ter infinitas recursões com
__getattr__
.Vou deixar isso como um exercício.
fonte
Eu acho que as outras respostas fizeram um ótimo trabalho em explicar a diferença entre
__getattr__
e__getattribute__
, mas uma coisa que pode não estar clara é por que você gostaria de usar__getattribute__
. O legal__getattribute__
é que ele essencialmente permite sobrecarregar o ponto ao acessar uma classe. Isso permite que você personalize como os atributos são acessados em um nível baixo. Por exemplo, suponha que eu queira definir uma classe em que todos os métodos que usam apenas um argumento próprio sejam tratados como propriedades:E do intérprete interativo:
Claro que este é um exemplo bobo e você provavelmente nunca iria querer fazer isso, mas mostra o poder que você pode obter com a substituição
__getattribute__
.fonte
Passei pela excelente explicação de outros. No entanto, eu encontrei uma resposta simples neste blog Python Magic Methods e
__getattr__
. Todos os seguintes são de lá.Usando o
__getattr__
método mágico, podemos interceptar essa pesquisa inexistente de atributo e fazer algo para que não falhe:Mas se o atributo existir,
__getattr__
não será chamado:__getattribute__
é semelhante a__getattr__
, com a diferença importante que__getattribute__
interceptará TODAS as pesquisas de atributo, não importa se o atributo existe ou não.Nesse exemplo, o
d
objeto já possui um valor de atributo. Mas quando tentamos acessá-lo, não obtemos o valor esperado original ("Python"); estamos apenas recebendo o que quer que seja__getattribute__
devolvido. Isso significa que praticamente perdemos o atributo value; tornou-se "inacessível".fonte