3.3.2.3 Invocare i descrittori

Generalmente, un descrittore è un oggetto attributo che ha un ``comportamento limitato'', cioè accessi ad attributi sovrascritti dai metodi del suo protocollo: __get__(), __set__() e __delete__(). Si definisce descrittore l'oggetto che ha qualcuno di questi metodi definito.

Il comportamento predefinito per l'accesso all'attributo è di ottenere ``get'', impostare ``set'', o cancellare ``delete'' l'attributo dal dizionario dell'oggetto. Per esempio a.x esegue una ricerca vincolata che parte da a.__dict__['x'], procede con type(a).__dict__['x'] e continua attraversando le classi base del type(a), escludendo le metaclassi.

Tuttavia, se il valore cercato è chiaramente un oggetto con definito uno dei metodi descrittori, Python allora può sovrascrivere il comportamento predefinito ed invocare, invece, il metodo descrittore. La precedenza con cui ciò avviene dipende da quali metodi descrittori sono stati definiti e da come sono chiamati. Notare che i descrittori vengono invocati solo per gli oggetti o le classi di nuovo stile (quelle che derivano da object() o type()).

L'invocazione più comune di un descrittore è il legame a.x. Come gli argomenti vengono assemblati dipende da a:

Chiamata diretta
La chiamata più semplice e più comune avviene quando il programmatore invoca direttamente un metodo descrittore: x.__get__(a).

Legame ad un'istanza
nel caso di un legame ad un'istanza di un oggetto di nuovo stile, a.x viene trasformato in chiamata: type(a).__dict__['x'].__get__(a, type(a)).

Legame ad una classe
nel caso di un legame ad una classe di nuovo stile, A.x viene trasformato in chiamata: A.__dict__['x'].__get__(None, A).

Super legame
Se a è un'istanza di super, allora il legame super(B, obj).m() ricerca obj.__class__.__mro__ per la classe base A immediatamente prima di B e poi invoca il descrittore mediante la chiamata: A.__dict__['m'].__get__(obj, A).

Per i legami d'istanza, la precedenza con cui avviene l'invocazione del descrittore dipende da come sono definiti i suoi metodi. I descrittori di dati definiscono entrambi __get__() e __set__(). Gli altri descrittori hanno solo il metodo __get__(). I descrittori di dati sovrascrivono sempre una ridefinizione in un dizionario d'istanza. D'altro canto, tutti gli altri descrittori possono essere sovrascritti dalle istanze.

I metodi di Python (compresi staticmethod() e classmethod()) non sono implementati come descrittori di dati. Quindi, le istanze possono ridefinire e sovrascrivere i metodi. Ciò permette alle singole istanze di acquisire comportamenti diversi dalle altre istanze della stessa classe.

La funzione property() viene implememtata come descrittore di dati. Perciò le istanze non possono sovrascrivere il comportamento di una proprietà.

Vedete Circa questo documento... per informazioni su modifiche e suggerimenti.