2009-12-22 10 views
28

Sé que este código es correcto:¿Cuál es la relación entre __getattr__ y getattr?

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 es falso:

# 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 debemos usar estas funciones (__getattr__ y getattr)?

+0

posible duplicado de [Comprender la diferencia entre \ _ \ _ getattr \ _ \ _ y \ _ \ _ getattribute \ _ \ _] (http://stackoverflow.com/questions/4295678/understanding-the-difference-between- getattr-and-getattribute) – Trilarion

+1

@Trilarion que no es un duplicado adecuado para esta pregunta –

Respuesta

47

respuesta de Alex era bueno, pero que le proporciona un código de ejemplo ya que preguntas por ella :)

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 respuesta corta es

Se utilizan

__getattr__ a definir cómo manejar los atributos que son no encontrado

y

getattr a obtener la atributos

+3

Tenga cuidado si usa '__getattr__' porque rompe el módulo' copy' incorporado a menos que también implemente '__copy__' y' __deepcopy__' para su clase. Me llevó algo de tiempo rastrear este error ... En 2.7 de todos modos –

33

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

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

Por lo tanto, el caso de uso principal para la función integrada getattr es cuando usted no tiene el nombre del atributo como una constante, sino más bien 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 proporcionar ese atributo (a través de __dict__, ranuras, propiedades, etc. encendido) todo falló. Puede definirlo, por ejemplo, cuando desee delegar búsquedas de atributos indefinidos a otros objetos.

Por lo tanto, su segundo ejemplo es incorrecto porque el getattr incorporado puede nunca se llamará con un solo argumento.

El tercero falla porque el diccionario del que está tratando de "obtener un atributo" no tiene ese atributo - tiene elementos, que son totalmente disjuntos de los atributos, por supuesto.

+2

Si bien tu respuesta es excelente, @ zjm1126 quería una muestra de código porque su inglés no es tan bueno. – Kimvais

14

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

getattr() es una función a la que puede llamar para intentar una búsqueda de miembro. Si la búsqueda tiene éxito, obtienes 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 caso de que falle la búsqueda.

Si declara una función de miembro __getattr__(), puede hacer que tenga éxito a veces, o puede hacer que tenga éxito todo el tiempo.

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 es siempre llamada en cada búsqueda. Es muy peligroso porque puede hacer que sea imposible acceder 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 a.v # 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 a.v!

+1

+1 por mencionar __getattribute__, de lo que supongo que se trataba en realidad la pregunta. – kibitzer

+0

Explicación simple y simple de __getattribute__ que siempre me había parecido poco clara. –

Cuestiones relacionadas