type define argument python getattr getattribute

python - define - Diferencia entre__getattr__ vs__getattribute__



list api python (5)

Este es solo un ejemplo basado en la explicación de Ned Batchelder .

__getattr__ ejemplo:

class Foo(object): def __getattr__(self, attr): print "looking up", attr value = 42 self.__dict__[attr] = value return value f = Foo() print f.x #output >>> looking up x 42 f.x = 3 print f.x #output >>> 3 print (''__getattr__ sets a default value if undefeined OR __getattr__ to define how to handle attributes that are not found'')

Y si se usa el mismo ejemplo con __getattribute__ , obtendría >>> RuntimeError: maximum recursion depth exceeded while calling a Python object

Estoy tratando de entender cuándo usar __getattr__ o __getattribute__ . La documentation menciona que __getattribute__ aplica a las clases de nuevo estilo. ¿Qué son las clases de nuevo estilo?



Las clases de nuevo estilo son las que subclase "objeto" (directa o indirectamente). Tienen un método de clase __new__ además de __init__ y tienen un comportamiento de bajo nivel algo más racional.

Por lo general, querrá anular __getattr__ (si también lo está anulando), de lo contrario, tendrá dificultades para admitir la sintaxis "self.foo" dentro de sus métodos.

Información adicional: http://www.devx.com/opensource/Article/31482/0/page/4


Una diferencia clave entre __getattr__ y __getattribute__ es que __getattr__ solo se invoca si el atributo no se encontró de la manera habitual. Es bueno para implementar un respaldo para los atributos que faltan, y es probablemente uno de los dos que desea.

__getattribute__ se invoca antes de mirar los atributos reales en el objeto, por lo que puede ser difícil de implementar correctamente. Puedes terminar en recursiones infinitas muy fácilmente.

Las clases de estilo nuevo se derivan del object , las clases de estilo antiguo son aquellas en Python 2.x sin una clase base explícita. Pero la distinción entre clases de estilo antiguo y de estilo nuevo no es lo importante al elegir entre __getattr__ y __getattribute__ .

Es casi seguro que quieres __getattr__ .


Veamos algunos ejemplos simples de los métodos mágicos __getattr__ y __getattribute__ .

__getattr__

Python llamará __getattr__ método __getattr__ cuando solicite un atributo que aún no se ha definido. En el siguiente ejemplo, mi clase Count no tiene ningún método __getattr__ . Ahora, en general, cuando intento acceder a los obj1.mymin y obj1.mymax todo funciona bien. Pero cuando intento acceder obj1.mycurrent atributo obj1.mycurrent , Python me da AttributeError: ''Count'' object has no attribute ''mycurrent''

class Count(): def __init__(self,mymin,mymax): self.mymin=mymin self.mymax=mymax obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.mycurrent) --> AttributeError: ''Count'' object has no attribute ''mycurrent''

Ahora mi clase Count tiene el método __getattr__ . Ahora cuando intento acceder obj1.mycurrent atributo obj1.mycurrent - python me devuelve lo que haya implementado en mi método __getattr__ . En mi ejemplo, cada vez que trato de llamar a un atributo que no existe, python crea ese atributo y lo establece en el valor entero 0.

class Count: def __init__(self,mymin,mymax): self.mymin=mymin self.mymax=mymax def __getattr__(self, item): self.__dict__[item]=0 return 0 obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.mycurrent1)

__getattribute__

Ahora veamos el método __getattribute__ . Si tiene el método __getattribute__ en su clase, python invoca este método para cada atributo, independientemente de si existe o no. Entonces, ¿por qué necesitamos el método __getattribute__ ? Una buena razón es que puede evitar el acceso a los atributos y hacerlos más seguros como se muestra en el siguiente ejemplo.

Cada vez que alguien intenta acceder a mis atributos que comienza con la subcadena ''cur'', python genera la excepción AttributeError . De lo contrario, devuelve ese atributo.

class Count: def __init__(self,mymin,mymax): self.mymin=mymin self.mymax=mymax self.current=None def __getattribute__(self, item): if item.startswith(''cur''): raise AttributeError return object.__getattribute__(self,item) # or you can use ---return super().__getattribute__(item) obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.current)

Importante: para evitar una recursión infinita en el método __getattribute__ , su implementación siempre debe llamar al método de clase base con el mismo nombre para acceder a los atributos que necesita. Por ejemplo: object.__getattribute__(self, name) o super().__getattribute__(item) y no self.__dict__[item]

IMPORTANTE

Si su clase contiene los métodos mágicos getattr y getattribute , entonces se llama primero a __getattribute__ . Pero si __getattribute__ genera una excepción AttributeError , la excepción se ignorará y se __getattr__ método __getattr__ . Vea el siguiente ejemplo:

class Count(object): def __init__(self,mymin,mymax): self.mymin=mymin self.mymax=mymax self.current=None def __getattr__(self, item): self.__dict__[item]=0 return 0 def __getattribute__(self, item): if item.startswith(''cur''): raise AttributeError return object.__getattribute__(self,item) # or you can use ---return super().__getattribute__(item) # note this class subclass object obj1 = Count(1,10) print(obj1.mymin) print(obj1.mymax) print(obj1.current)