¿Cuál es la relación entre __getattr__ y getattr?

Sé que este código es correcto:

class A: def __init__(self): self.a = 'a' def method(self): print "method print" a = A() print getattr(a, 'a', 'default') print getattr(a, 'b', 'default') print getattr(a, 'method', 'default') getattr(a, 'method', 'default')() 

Y esto está mal:

 # will __getattr__ affect the getattr? class a(object): def __getattr__(self,name): return 'xxx' print getattr(a) 

Esto también es incorrecto:

 a={'aa':'aaaa'} print getattr(a,'aa') 

¿Dónde deberíamos usar estas funciones ( __getattr__ y getattr )?

La respuesta de Alex fue buena, pero te proporcionó un código de muestra ya que lo pediste 🙂

 class foo: def __init__(self): self.a = "a" def __getattr__(self, attribute): return "You asked for %s, but I'm giving you default" % attribute >>> bar = foo() >>> bar.a 'a' >>> bar.b "You asked for b, but I'm giving you default" >>> getattr(bar, "a") 'a' >>> getattr(bar, "b") "You asked for b, but I'm giving you default" 

Así que en breve respuesta es

Tu usas

__getattr__ para definir cómo manejar los atributos que no se encuentran

y

getattr para obtener los atributos

getattr es una función incorporada que toma (al menos) dos argumentos: el objeto del cual se obtiene el atributo y el nombre de la cadena del atributo.

Si el nombre de la cadena es una constante, diga 'foo' , getattr(obj, 'foo') es exactamente lo mismo que obj.foo .

Por lo tanto, el caso de uso principal para la función getattr es cuando no tiene el nombre del atributo como una constante, sino como una variable. Un segundo caso de uso importante es cuando le pasa tres argumentos, en lugar de solo dos: en ese caso, si el atributo está ausente del objeto, getattr devuelve el tercer argumento, “predeterminado”, en lugar de generar una excepción.

__getattr__ es un método especial, definido en una clase, que se invoca cuando se solicita algún atributo de una instancia de esa clase, y otras formas normales de suministrar ese atributo (a través de __dict__ , ranuras, propiedades, etc. de la instancia) fallaron . Puede definirlo, por ejemplo, cuando desee delegar búsquedas de atributos no definidos de otra manera a otros objetos.

Entonces, su segundo ejemplo es incorrecto porque nunca se puede llamar al getattr incorporado con un solo argumento.

La tercera falla porque el diccionario del que está intentando “obtener un atributo” no tiene ese atributo, tiene elementos , que por supuesto están totalmente separados de los atributos.

__getattr__() es una función de método especial que puede definir. Cuando una búsqueda de miembros falla, esta función será llamada.

getattr() es una función a la que puede llamar para intentar realizar una búsqueda de miembros. Si la búsqueda se realiza correctamente, obtiene el miembro (quizás un objeto de función de método, o quizás un objeto de atributo de datos). getattr() también puede devolver un valor predeterminado en el caso de que la búsqueda falle.

Si declara una función miembro __getattr__() , puede hacer que tenga éxito algunas veces, o puede hacer que tenga éxito cada vez.

 class A(object): def __getattr__(self, name): return "I pretend I have an attribute called '%s'" % name a = A() print a.foo # prints "I pretend I have an attribute called 'foo'" 

Python también tiene __getattribute__() que siempre se __getattribute__() en cada búsqueda. Es muy peligroso porque puede imposibilitar el acceso a los miembros normalmente.

 class A(object): def __init__(self, value): self.v = value def __getattribute__(self, name): return "I pretend I have an attribute called '%s'" % name a = A(42) print av # prints "I pretend I have an attribute called 'v'" print a.__dict__["v"] # prints "I pretend I have an attribute called '__dict__'" 

Vaya, ahora es imposible acceder a av!