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
:
x.__get__(a)
.
a.x
viene trasformato in chiamata:
type(a).__dict__['x'].__get__(a, type(a))
.
A.x
viene trasformato in chiamata:
A.__dict__['x'].__get__(None, A)
.
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.