Voglio sovrascrivere il __getattr__
metodo su una classe per fare qualcosa di elegante, ma non voglio interrompere il comportamento predefinito.
Qual è il modo corretto per farlo?
Voglio sovrascrivere il __getattr__
metodo su una classe per fare qualcosa di elegante, ma non voglio interrompere il comportamento predefinito.
Qual è il modo corretto per farlo?
Risposte:
L'override __getattr__
dovrebbe andare bene - __getattr__
viene chiamato solo come ultima risorsa, cioè se nell'istanza non ci sono attributi che corrispondono al nome. Ad esempio, se si accede foo.bar
, __getattr__
verrà chiamato solo se foo
non ha alcun attributo chiamato bar
. Se l'attributo è uno che non vuoi gestire, aumenta AttributeError
:
class Foo(object):
def __getattr__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
raise AttributeError
Tuttavia, diversamente __getattr__
, __getattribute__
verrà chiamato per primo (funziona solo per le nuove classi di stile, cioè quelle che ereditano dall'oggetto). In questo caso, puoi conservare il comportamento predefinito in questo modo:
class Foo(object):
def __getattribute__(self, name):
if some_predicate(name):
# ...
else:
# Default behaviour
return object.__getattribute__(self, name)
__getattr__
- qualche idea su cosa fare? ( AttributeError: 'super' object has no attribute '__getattr__'
)
AttributeError
senza il contesto dell'attributo negli argomenti di eccezione.
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()
>>> a.a
42
>>> a.b
42
>>> a.missing
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 8, in __getattr__
AttributeError: 'A' object has no attribute 'missing'
>>> hasattr(a, "b")
True
>>> hasattr(a, "missing")
False
self.__class__.__name__
dovrebbe essere usato invece che self.__class__
nel caso in cui la classe abbia la precedenza__repr__
Per estendere la risposta di Michael, se si desidera mantenere il comportamento predefinito utilizzando __getattr__
, è possibile farlo in questo modo:
class Foo(object):
def __getattr__(self, name):
if name == 'something':
return 42
# Default behaviour
return self.__getattribute__(name)
Ora il messaggio di eccezione è più descrittivo:
>>> foo.something
42
>>> foo.error
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getattr__
AttributeError: 'Foo' object has no attribute 'error'
__getattr__
e __getattribute__
?