[Python] Problema con __getattr__
Daniele Varrazzo
piro a develer.com
Lun 27 Ott 2008 03:04:34 CET
On Sun, 26 Oct 2008 22:44:41 +0100, Listemessaggi CoPlast
<listemessaggi a coplast.eu> wrote:
> Ma se come detto, faccio l'overloading di questo operatore, cioè con:
>
> class Commuter:
> def __init__(self, val):
> self.val = val
> def __getattr__(self, nome):
> print("BO")
>
> se scrivo:
>
> c = Commuter(23)
> print(c)
>
> ottengo:
>
> BO
> Traceback (most recent call last):
> File "libreria.py", line 83, in ?
> print(c)
> TypeError: 'NoneType' object is not callable
>
>
> Osservo che ha scritto BO segno che è passato per __getattr__. Ma
> perché?
> Forse viene interpretato come una qualificazione di un attributo di nome
> "" (senza nome)?
> Se su def __getattr__(self, nome): ci inserisco un print(nome) ottengo:
> __str__
> Ciò mi mette ancora più in confusione.
__getattr__ viene invocato quando un attributo non viene trovato
nell'oggetto. Quando fai "print c", Python chiede a 'c' il metodo __str__,
che viene usato per convertire l'oggetto in stringa. Poiché non hai
definito __str__, questo viene chiesto a __getattr__ (come verifichi).
Nella tua definizione di __getattr__ c'è un "return None" implicito alla
fine: Python riceve qualcosa dal tuo oggetto e pensa che sia il metodo
__str__: quindi prova ad invocarlo. Quello che fa invece è provare a
invocare None(), che risulta nell'errore che riporti.
Il problema di come hai definito tu __getattr__ è che "va sempre tutto
bene", salvo poi che il runtime pensa di avere un oggetto callable con la
semantica di __str__ mentre invece ha un None. Dovresti implementare il tuo
__getattr__ in maniera da rispondere solo a quello che si aspetta e dare
errore negli altri casi. Per esempio:
class Commuter:
def __init__(self, val):
self.val = val
def __getattr__(self, nome):
print(nome)
raise AttributeError("%s has no attribute '%s'"
% (self.__class__.__name__, nome))
>>> print c
__str__
__repr__
<__main__.Commuter instance at 0xb78397cc>
>>> c.ciao
ciao
ciao
---------------------------------------------------------------------------
<type 'exceptions.AttributeError'> Traceback (most recent call
last)
/home/piro/<ipython console> in <module>()
<type 'exceptions.AttributeError'>: Commuter has no attribute 'ciao'
> Comunque il mio obiettivo sarebbe quello di usare __radd__ solo che il
> mio oggetto ha sia la __radd__ che la __getattr__ e quest'ultima fa in
> modo che la __radd__ non riceva correttamente l'istanza del mio oggetto
> impedendomi di usarla.
La semantica è quella di invocare __getattr__ solo se l'attributo cercato
non viene trovato, quindi __radd__ non dovrebbe conflittare: dovrebbe
essere cercato *prima* di getattr. Probabilmente, per come poi usi la tua
classe, non è __radd__ ad essere invocato. La strada per il debug l'hai
azzeccata: un print nel __getattr__ va bene. Aggiungi il raise
AttributeError alla fine e scoprirai qual'è il metodo che ti serve.
--
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com
Maggiori informazioni sulla lista
Python