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

Daniele Varrazzo piro a develer.com
Lun 30 Giu 2008 02:43:22 CEST


Francesco Stablum ha scritto:

> Le metaclassi sono molto interessanti, cosi' come tutto l'aspetto di
> introspezione del python e
> le magnifiche lambda. Ho come l'impressione che tutti questi elementi
> manderanno in pensione
> un sacco di design pattern descritti in letteratura.

Questo è abbastanza comune: quelli che sono "pattern" in linguaggi di 
programmazione di più basso livello tendono a diventare elementi di base in 
linguaggi di livello più alto. Per esempio l'Iteratore poteva essere 
considerato un "pattern" in C (ovvero una best practice, non rafforzata dal 
linguaggio in se, ma riconosciuta come la soluzione migliore per una certa 
classe di problemi), ma già in C++ è diventato qualcosa di centrale nel design 
dell'STL e in Python è praticamente l'unico modo di visitare una collezione - 
il for come "contatore" non c'è nemmeno nel linguaggio.

Quelli attualmente conosciuti come pattern non sono però da mandare in 
pensione, anzi: con un linguaggio espressivo come il Python diventano facili 
da implementare e la loro barriera di introduzione si abbassa. Ma sono 
elementi "architettonici" di un sistema informatico: prendi il pattern Facade: 
ti può aiutare a disaccoppiare due aree di un programma, non ha niente a che 
vedere con il linguaggio in cui è implementato. Probabilmente è più facile 
farlo in Python che in C++... quindi non ci sono scuse per non farlo!

> per Marco:
> e' vero, avrei potuto anche utilizzare direttamente property() ma nel
> caso di un gran numero
> di variabili d'istanza diventa troppo ripetitivo ogni volta dover
> specificare che il getter/setter di "foobar"
> e' get_foobar/set_foobar.

Però pensa a questo: se hai davvero così tanti di questi oggetti da dover 
trattare che vuoi farlo in maniera più automatica possibile... allora quale 
sarà il comportamento di tutti? Non mi viene difficile pensare che, per la 
maggior parte dei casi, sarà

     def set_foo(self, foo):
         self._foo = foo

     def get_foo(self):
         return self._foo

ma allora, a questo punto, perché non lasci che foo sia un normale attributo?

> A livello di quantita' di codice cerco le soluzioni piu' "riassuntive"
> possibili.

Non avere niente è la quantità minima di codice (ha anche altre interessanti 
proprietà, per esempio è autoreplicante...)

Probabilmente hai letto papiri in altri linguaggi che ti hanno insegnato a 
nascondere sempre lo stato e fornire sempre metodi di accesso. Ma il problema 
in questi linguaggi è che passare da un attributo pubblico a un getter 
richiede un refactoring a tappeto, perché in Java/C++ la sintassi è diversa 
(devi passare da "foo.bar" a "foo.bar()", e da "foo.bar = x" a 
"foo.setBar(x)"), quindi ti consigliano di partire direttamente da questa 
sintassi.

In Python questo problema non esiste: puoi cominciare a creare oggetti con 
attributi pubblici, che andranno bene per la stragrande maggioranza dei casi. 
Per quei pochi casi in cui ti serve un getter o un setter un po' più fancy, 
puoi nascondere l'attributo foo in un __foo privato e aggiungere una property 
"foo" che richiama _get_foo() e _set_foo(): tutto il codice che utilizzava la 
tua classe continua a funzionare indisturbato.

Insomma, ti sei accorto che in Python si possono fare in automatico molte cose 
che in Java o in C++ andavano noiosamente fatte a mano... peccato che poi ci 
si accorga anche che alcune di quelle cose non ha più neanche tanto senso farle!

A presto!

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


Maggiori informazioni sulla lista Python