¿Cómo invalido __getattr__ en Python sin romper el comportamiento predeterminado?

Quiero anular el método __getattr__ en una clase para hacer algo sofisticado, pero no quiero romper el comportamiento predeterminado.

¿Cuál es la forma correcta de hacer esto?

La __getattr__ debería estar bien: __getattr__ solo se llama como último recurso, es decir, si no hay atributos en la instancia que coincidan con el nombre. Por ejemplo, si accede a foo.bar , entonces __getattr__ solo se llamará si foo no tiene ningún atributo llamado bar . Si el atributo es uno que no desea manejar, genere AttributeError :

 class Foo(object): def __getattr__(self, name): if some_predicate(name): # ... else: # Default behaviour raise AttributeError 

Sin embargo, a diferencia de __getattr__ , __getattribute__ se llamará primero (solo funciona para las nuevas clases de estilo, es decir, las que heredan de un objeto). En este caso, puede preservar el comportamiento predeterminado de esta manera:

 class Foo(object): def __getattribute__(self, name): if some_predicate(name): # ... else: # Default behaviour return object.__getattribute__(self, name) 

Ver los documentos de Python para más .

 class A(object): def __init__(self): self.a = 42 def __getattr__(self, attr): if attr in ["b", "c"]: return 42 raise AttributeError("%r object has no attribute %r" % (self.__class__.__name__, attr)) 

 >>> a = A() >>> aa 42 >>> ab 42 >>> a.missing Traceback (most recent call last): File "", line 1, in  File "", line 8, in __getattr__ AttributeError: 'A' object has no attribute 'missing' >>> hasattr(a, "b") True >>> hasattr(a, "missing") False 

Para extender la respuesta de Michael, si desea mantener el comportamiento predeterminado usando __getattr__ , puede hacerlo así:

 class Foo(object): def __getattr__(self, name): if name == 'something': return 42 # Default behaviour return self.__getattribute__(name) 

Ahora el mensaje de excepción es más descriptivo:

 >>> foo.something 42 >>> foo.error Traceback (most recent call last): File "", line 1, in  File "", line 5, in __getattr__ AttributeError: 'Foo' object has no attribute 'error'