Un descrittore è un oggetto che implementa uno qualsiasi dei metodi get, set e delete. Consente di controllare l'accesso agli attributi della classe.
Metodi standard del descrittore:
__get__(self, instance, owner)__set__(self, instance, value)__delete__(self, instance)I descrittori possono essere:
Esempio di utilizzo:
class OnlyPositive: def __init__(self): self._name = '_value' def __get__(self, instance, owner): return instance.__dict__[self._name] def __set__(self, instance, value): if value < 0: raise ValueError('Il valore deve essere >= 0') instance.__dict__[self._name] = value class Account: value = OnlyPositive() def __init__(self, value): self.value = value acc = Account(10) acc.value = -1 # ValueError!
property è solo zucchero sintattico per creare descrittori a livello di classe.
Cosa succede se si crea un descrittore come attributo di un'istanza, e non di una classe?
Molti pensano che il descrittore funzionerà, ma non è così.
Risposta corretta:
Il descrittore funziona solo se definito direttamente come attributo della classe. Se si imposta un descrittore come attributo dell'istanza, i metodi get/set non verranno chiamati — si utilizza la logica normale di accesso all'attributo.
Storia
Utilizzo di property invece di un vero descrittore
Per la validazione e altri attributi correlati, lo sviluppatore utilizzava una semplice property, il che portava a una frequente duplicazione della logica e all'impossibilità di riutilizzare il codice tra diverse classi.
Storia
Non rispetto dell'immutabilità durante il riutilizzo dello storage
Il descrittore memorizzava dati in un attributo interno della propria classe (self.x), e non nello storage interno dell'istanza, portando a un attributo "comune", e diversi istanze della classe sovrascrivevano i valori l'uno dell'altro — i dati "trapelavano" tra oggetti.
Storia
Scambiati descrittore di dati e descrittore non di dati
In una gerarchia complessa è stata tralasciata l'implementazione di set, impedendo così a un attributo normale dell'istanza di sovrascrivere il descrittore, rompendo l'intero meccanismo di validazione — il bug si manifestava non sempre, difficile da debug.