[Python] override di __getattribute__ per avere getter e setter "automatici"

Daniele Varrazzo piro a develer.com
Dom 29 Giu 2008 19:07:56 CEST


Francesco Stablum ha scritto:
> Un saluto a tutti,
> mi chiamo Francesco e sono nuovo della lista :-)

Ciao!

> Ho cominciato ad usare il python un paio di mesi fa per lavoro e lo
> trovo un linguaggio estremamente interessante e potente, soprattutto
> sul versante dell'introspezione.
> 
> Vorrei condividere con voi del codice che ho scritto per creare setter
> e getter "automatici".
> 
> potete visionarlo al seguente url:
> http://rafb.net/p/bQDQAF11.html
> 
> l'obiettivo e' quello di creare un "sostituto" di "object" per
> estendere le sue funzionalita' e dare la possibilita'
> di definire variabili d'istanza con l'override degli operatori
> "assegnazione" e "lettura".
> 
> Per raggiungere questo scopo ho ridefinito i metodi __getattribute__ e
> __setattr__
> 
> l'obiettivo e' quello che un pezzo di codice come questo:
> 
> obj.foobar = 42
> 
> chiami il metodo "set_foobar(42)" definito dentro "obj"
> 
> come vi sembra come idea e come design?

E' un classico:

http://www.python.org/download/releases/2.2.3/descrintro/#metaclass_examples

tra l'altro anche io appena cominciato col Python ho sentito la necessità 
impellente di realizzare qualcosa del genere. Ho idea ci si passi tutti :)

Questo è un lavoro da metaclasse, non da clase di base, per almeno un paio di 
motivi. Il primo è di efficienza: con una metaclasse il codice decisionale 
viene spostato a compile time e non a runtime: nei tuoi oggetti il "getattr" - 
una delle operazioni più frequenti del linguaggio, passa attraverso ben due try.

Il secondo è di design: l'albero di ereditarietà è più adatto per progettare 
un modello di dominio, non tanto per cambiare il comportamento di base di un 
oggetto (da questo punto di vista è fuorviante che esista un "object" come 
classe di base per creare le "new style classes", ma questo è un tradeoff che 
è stato necessario per garantire la convivenza di nuove e vecchie classi senza 
aggiungere ulteriori elementi sintattici nel linguaggio: in Python 3.0 sparirà).

Al di là di questo... tipicamente non serve aggiungere tanta magia all'oggetto 
fondamentale del linguaggio. A meno che magari questo non faccia parte di un 
framework per cui ogni getattr/setattr fa tanta magia: credo che PEAK 
(http://peak.telecommunity.com/) facesse qualcosa del genere. (Il Python 
Enterprise Application Kit non è stato esattamente accolto a braccia aperte: 
credo faccia parte della mentalità del Python tenere le cose semplici e senza 
troppa magia).

> inoltre ho un problemino: non riesco ad accedere alla variabile
> "__foobar"  all'interno del metodo __getattribute__
> avete qualche idea? (il problema e' segnato con un FIXME all'interno
> del codice all'url http://rafb.net/p/bQDQAF11.html )

Non puoi accedere a variabili "__private" se non dalla stessa classe: né 
sottoclassi né sopraclassi possono farlo. Devi usare variabili "_protette", 
con un solo underscore.

Divertiti! Io ho ancora codice sparso in giro da qualche cliente che usava 
cose di questo genere. Forse anche paggio (tipo un recordset all'interno di un 
wrapper di getter/setter)... ne sono uscito, ma è stato istruttivo ;)

-- 
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com


Maggiori informazioni sulla lista Python