ProgrammazioneSviluppatore Backend

Quali sono i decoratori di classe in Python? Come possono essere utilizzati per modificare o arricchire la funzionalità delle classi? Fornisci un esempio e parla di eventuali sfumature.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Un decoratore di classe è una funzione che accetta una classe come argomento e restituisce una classe modificata o completamente nuova. Con essi è possibile aggiungere dinamicamente metodi, modificare il comportamento dei metodi esistenti o persino restituire una sottoclasse che estende la funzionalità della classe originale.

Esempio più semplice di decoratore di classe:

def add_repr(cls): def __repr__(self): return f'<{cls.__name__}: {self.__dict__}>' cls.__repr__ = __repr__ return cls @add_repr class Point: def __init__(self, x, y): self.x = x self.y = y p = Point(3, 4) print(p) # <Point: {'x': 3, 'y': 4}>
  • Il decoratore add_repr aggiunge dinamicamente il metodo __repr__ a tutte le classi a cui è applicato.

Sfide:

  • I decoratori di classe possono restituire non solo incapsulamenti nella classe, ma anche classi completamente avvolte (ad esempio, classi proxy o eredi).
  • Potrebbero verificarsi errori se il decoratore non supporta gli argomenti *args e **kwargs, utilizzati nella creazione delle istanze della classe.

Domanda trabocchetto.

Cosa succede se si applicano due decoratori di classe uno dopo l'altro? L'ordine della loro applicazione è sempre ovvio?

Risposta:

I decoratori vengono applicati "dal basso verso l'alto": prima viene applicato il decoratore direttamente sopra la dichiarazione della classe, poi quello sopra e così via. L'ordine è MOLTO IMPORTANTE, poiché il risultato del primo decoratore viene passato al secondo e così via.

@dec1 @dec2 class Test: ... # Equivalente a: # Test = dec1(dec2(Test))

Esempi di errori reali dovuti alla mancata conoscenza delle sfumature del tema.


Storia

In un'applicazione e-commerce volevano registrare i metodi della classe, ma accidentalmente hanno restituito un oggetto errato dal decoratore, e i metodi hanno perso le loro proprietà della classe, causando problemi di ereditarietà e interrompendo il funzionamento del modello.


Storia

In un progetto per la generazione automatica di nuovi metodi è stato utilizzato un decoratore aggiuntivo, ma si sono dimenticati di chiamare super() durante il ritorno della sottoclasse. Di conseguenza, l'ereditarietà e il MRO sono stati compromessi, causando chiamate non funzionanti della classe base nelle classi figlie.


Storia

In un data pipeline hanno cercato di avvolgere le classi con diversi decoratori (logger, tracker dei cambiamenti), ma a causa di un ordine di applicazione errato hanno ottenuto conflitti nei nomi dei metodi, causando bug in produzione a causa di metodi "persi".