lettura facile

Il metodo __set__() in Python

Il metodo speciale `__set__()` di Python fa parte del mondo dei "descriptor", un concetto un po' meno comune per chi inizia, ma molto potente se vuoi avere un controllo avanzato sui comportamenti di accesso e modifica degli attributi di un oggetto.

Cos'è un descriptor? Un descriptor (descrittore), in sostanza, è un oggetto che controlla il modo in cui un attributo viene recuperato, impostato o cancellato. Il linguaggio Python usa metodi speciali come `__get__()`, `__set__()` e `__delete__()` per fornire questa funzionalità.

Il metodo `__set__()` di un descriptor viene chiamato automaticamente ogni volta che si prova a impostare il valore di un attributo gestito dal descriptor.

È una sorta di "guardiano", che dice: "Ogni volta che tenti di cambiare il valore di questo attributo, io ho qualcosa da dire!".

Può decidere di permettere l'operazione, modificarla, o persino bloccarla.

class Descriptor:
    def __set__(self, instance, value):
       # code
       pass

Dove

  • Self è il descrittore
  • Instance è l'oggetto che contiene l'attributo
  • Value è il nuovo valore che si sta tentando di assegnare

Vediamo come usarlo nella pratica con un esempio pratico.

Supponi di voler creare una classe che rappresenti una persona con un'età, ma vuoi essere sicuro che l'età sia sempre positiva (perché non ha senso che una persona abbia un'età negativa, giusto?).

Per fare questo controllo puoi usare il metodo `__set__()` in una classe descrittore.

class PositiveAgeDescriptor:
    def __set__(self, instance, value):
        if value < 0:
            raise ValueError("L'età non può essere negativa!")
        instance.__dict__['age'] = value  # Salviamo l'attributo nell'oggetto
    
    def __get__(self, instance, owner):
        return instance.__dict__.get('age', None)

In questa classe descriptor chiamata 'PositiveAgeDescriptor' il metodo `__set__()` viene invocato quando tenti di assegnare un valore all'attributo `age`.

All'interno, il metodo controlla se il valore è negativo. Se lo è, solleva un errore. Se non lo è, salva l'età nell'oggetto `instance` utilizzando `__dict__`.

Nella classe descriptor c'è anche il metodo `__get__()` che viene chiamato quando si cerca di accedere al valore dell'attributo. Nel nostro caso, lo recuperiamo da `__dict__`, il dizionario che Python usa per memorizzare gli attributi degli oggetti.

Ora crea una classe 'Persona' che richiama il descrittore per definire un attributo.

class Persona:
    age = PositiveAgeDescriptor()

Crea un'istanza della classe Persona

p = Persona()

Assegna all'attributo 'age' un valore positivo.

p.age = 25 

Quando cambi il valore dell'attributo 'age', l'oggetto chiama direttamente la classe descriptor `PositiveAgeDescriptor` che controlla se il valore è negativo tramite il metodo '__set__()'.

In questo caso, il valore è positivo e il controllo viene soddisfatto. Pertanto, il valore viene memorizzato regolarmente.

Se accedi all'attributo, trovi il valore che hai indicato.

print(p.age) 

25

Se invece assegni un valore negativo, il descrittore solleva un errore: ValueError.

p.age = -5 

ValueError: L'età non può essere negativa!

Quindi, pensa a un descriptor come un controllo aggiuntivo. Se qualcosa non va (ad esempio, un valore negativo che rappresenta una corrente "impossibile"), il dispositivo blocca il tutto e ti dà un avviso!

In conclusione, il metodo `__set__()` può sembrare complicato, ma alla fine non è altro che un modo per fare un controllo sul comportamento di un attributo.

Puoi usarlo per validare input, trasformare dati o persino modificare come gli attributi vengono memorizzati.




Se qualcosa non ti è chiaro, scrivi la tua domanda nei commenti.




FacebookTwitterLinkedinLinkedin