Python @staticmethod - quando usarlo e quali errori evitare

11 giugno 2026

Esempio di python static method: mostra come usarlo, che non funziona con oggetti e come chiamarlo tramite la classe.

Indice

Quando una funzione appartiene chiaramente a una classe, ma non ha bisogno né di self né di cls, @staticmethod offre una soluzione semplice e leggibile. In questo articolo mostro come funziona una static method in Python, quando conviene usarla, come distinguerla da un metodo di istanza o di classe e quali errori evitare, anche negli esempi legati all’accesso ai database.

La regola essenziale per usare bene i metodi statici

  • Nessun self o cls: il metodo non riceve automaticamente né l’istanza né la classe.
  • Funzione organizzata nella classe: è utile quando il comportamento appartiene concettualmente a quella classe.
  • Chiamata flessibile: puoi usarlo sia dalla classe sia da un’istanza.
  • Non sostituisce sempre una funzione di modulo: se il legame con la classe è debole, una funzione normale può essere più chiara.
  • Nei database non basta per la sicurezza: la costruzione delle query deve comunque usare parametri e API appropriate.

Diagramma che illustra la differenza tra variabili d'istanza e statiche in Python. Le variabili statiche sono condivise tra tutte le istanze.

Che cosa fa davvero @staticmethod

Un metodo statico è una funzione definita dentro una classe che Python non lega automaticamente all’oggetto chiamante. In pratica, quando lo invoco, non viene aggiunto alcun primo argomento nascosto: né l’istanza né la classe entrano nella chiamata.

class Convertitore:

    @staticmethod
    def metri_in_chilometri(metri):
        return metri / 1000

print(Convertitore.metri_in_chilometri(3500))
# 3.5

Il decoratore @staticmethod comunica una scelta precisa. La funzione è collocata dentro Convertitore perché riguarda quel concetto, ma il suo risultato dipende soltanto dai parametri ricevuti. Io lo considero soprattutto uno strumento di organizzazione del codice, non un modo per rendere una funzione più veloce o più potente.

È possibile chiamarla anche da un’istanza:

convertitore = Convertitore()
print(convertitore.metri_in_chilometri(2000))
# 2.0

La chiamata funziona, ma l’istanza non viene usata. Per questo preferisco la forma Convertitore.metri_in_chilometri(...), che rende subito evidente l’assenza di stato interno.

Come definire un metodo statico utile

Un buon esempio è una funzione di normalizzazione. Immaginiamo una classe che gestisce codici cliente provenienti da file, API o database. La normalizzazione non deve leggere attributi dell’oggetto e può quindi vivere come metodo statico.

class CodiceCliente:

    @staticmethod
    def normalizza(valore):
        if not isinstance(valore, str):
            raise TypeError("Il codice deve essere una stringa")

        return valore.strip().upper().replace(" ", "")

codice = CodiceCliente.normalizza(" ab 12 ")
print(codice)
# AB12

Qui la funzione è deterministica: allo stesso input corrisponde lo stesso output, senza dipendere da configurazioni esterne o attributi dell’istanza. Questo la rende facile da testare e adatta a essere riutilizzata in più punti dell’applicazione.

Un caso pratico con i dati del database

Nei progetti reali capita spesso di ricevere righe dal database e dover controllare che abbiano una forma valida prima di trasformarle in oggetti. Il metodo statico può occuparsi della validazione, mentre la connessione resta responsabilità del repository.

class UtenteRepository:

    @staticmethod
    def riga_valida(riga):
        if not isinstance(riga, tuple):
            return False

        if len(riga) != 3:
            return False

        id_utente, email, stato = riga

        return (
            isinstance(id_utente, int)
            and isinstance(email, str)
            and "@" in email
            and stato in {"attivo", "sospeso"}
        )

    def salva_riga(self, connessione, riga):
        if not self.riga_valida(riga):
            raise ValueError("Riga utente non valida")

        connessione.execute(
            "INSERT INTO utenti (id, email, stato) VALUES (?, ?, ?)",
            riga
        )

La funzione riga_valida() non sa nulla della connessione e non esegue query. Questa separazione è importante perché evita di mescolare validazione, accesso ai dati e gestione della transazione. Naturalmente, un metodo statico non rende automaticamente sicuro il codice SQL: per i valori dinamici servono sempre query parametrizzate.

La differenza tra metodo statico, di istanza e di classe

La scelta diventa più semplice se guardo al tipo di informazione di cui il metodo ha bisogno. Un metodo di istanza riceve normalmente self, un metodo di classe riceve cls, mentre uno statico non riceve alcun riferimento implicito.

Tipo Argomento automatico Quando usarlo Esempio tipico
Metodo di istanza self Quando legge o modifica i dati dell’oggetto Modificare l’indirizzo di un cliente
Metodo di classe cls Quando lavora con la classe o crea nuove istanze Creare un oggetto partendo da una riga SQL
Metodo statico Nessuno Quando serve una funzione collegata concettualmente alla classe Validare o normalizzare un valore

Per esempio, una factory che costruisce un utente da una riga del database è spesso più adatta a @classmethod, perché deve poter creare anche istanze di eventuali sottoclassi.

class Utente:

    def __init__(self, id_utente, email):
        self.id_utente = id_utente
        self.email = email

    @classmethod
    def da_riga(cls, riga):
        return cls(riga[0], riga[1])

    @staticmethod
    def email_valida(email):
        return isinstance(email, str) and "@" in email

In questo esempio email_valida() controlla soltanto il valore, mentre da_riga() usa cls per costruire l’oggetto corretto. Confondere i due ruoli porta spesso a classi meno flessibili, soprattutto quando il progetto cresce o introduce sottoclassi.

Quando conviene usarlo e quando evitarlo

Io uso un metodo statico quando la funzione ha un legame semantico evidente con la classe, ma non ha bisogno del suo stato. Un validatore per gli ordini dentro Ordine è comprensibile; una funzione matematica generica inserita in una classe solo per raccogliere codice lo è molto meno.

  • Usalo per validazioni, conversioni e parsing legati a un dominio preciso.
  • Usalo per piccoli helper chiamati da altri metodi della stessa classe.
  • Usalo quando il nome della classe rende la funzione più facile da trovare e capire.
  • Preferisci una funzione a livello di modulo se il comportamento è generale e indipendente dalla classe.

Una funzione di modulo è spesso la scelta migliore quando potrebbe essere riutilizzata da molte parti dell’applicazione. Inserire tutto nelle classi solo per mantenere un’organizzazione apparentemente ordinata crea il rischio di trasformare le classi in semplici contenitori di funzioni.

C’è anche un limite importante nei test. Un metodo statico è facile da testare se è puro, ma se legge file, variabili globali, orologio di sistema o servizi esterni, il decoratore non risolve il problema della dipendenza. In quel caso servono iniezione delle dipendenze, interfacce più chiare o una separazione architetturale migliore.

Gli errori più comuni con @staticmethod

Aggiungere self senza motivo

class Calcolatore:

    @staticmethod
    def somma(self, a, b):
        return a + b

Questo metodo non riceve automaticamente self, ma la firma lo richiede comunque. La chiamata Calcolatore.somma(2, 3) produrrà un errore perché mancherà un argomento. Se la funzione non usa l’istanza, rimuovere self è la correzione giusta.

Usare self o cls dentro il corpo

class Profilo:

    nome_predefinito = "Ospite"

    @staticmethod
    def descrizione():
        return self.nome_predefinito

Il codice fallisce perché self non esiste in quel contesto. Se serve un attributo dell’istanza, bisogna usare un metodo normale; se serve un attributo della classe, la soluzione più naturale è spesso @classmethod.

Confondere ordine e sicurezza delle query

Un metodo statico può validare un identificatore o preparare una struttura dati, ma non deve essere presentato come una protezione completa contro l’injection. Tabelle, colonne e valori hanno regole diverse, quindi per le parti dinamiche è necessario seguire le possibilità offerte dal driver del database e mantenere separati parametri e istruzioni SQL.

Leggi anche: Ciclo for in Python - guida a range, enumerate, zip e SQLite

Usarlo soltanto per imitare altri linguaggi

Chi arriva da Java o C# tende a cercare subito l’equivalente dei metodi statici. In Python, però, una funzione di modulo è spesso più idiomatica. La domanda che mi pongo è semplice: la classe aiuta davvero a capire dove appartiene questa funzione? Se la risposta è no, non forzo la scelta.

Il criterio pratico per scegliere senza complicare il codice

Prima di aggiungere @staticmethod, verifico tre cose. La funzione deve avere bisogno solo dei parametri espliciti, deve essere collegata in modo chiaro alla classe e deve diventare più facile da trovare grazie a quella collocazione.

Se usa dati dell’oggetto, scelgo un metodo di istanza. Se crea o gestisce oggetti usando la classe, considero @classmethod. Se è una trasformazione indipendente ma specifica del dominio della classe, il metodo statico è spesso il compromesso più pulito.

La sintassi è minima, ma la decisione architetturale conta. Un metodo statico ben scelto rende il codice più leggibile e i test più semplici; usato senza un vero legame con la classe, aggiunge soltanto un livello di indirezione che il progetto non aveva bisogno di avere.

Domande frequenti

Conviene quando la funzione ha un legame semantico evidente con una classe, ma non usa dati dell’istanza o della classe. È adatto, per esempio, a validazioni, conversioni e parsing specifici del dominio. Se il comportamento è generale e riutilizzabile in molte parti dell’applicazione, una funzione di modulo è spesso più chiara.

Il metodo di istanza riceve automaticamente self e può leggere o modificare i dati dell’oggetto. Il metodo di classe riceve cls e può lavorare sulla classe o creare istanze, come una factory da una riga SQL. Il metodo statico non riceve alcun riferimento implicito e usa solo gli argomenti espliciti.

Un repository può definire un metodo statico come riga_valida() per verificare tipo, numero e contenuto dei campi di una tupla, senza conoscere la connessione. Il metodo che salva i dati resta responsabile dell’accesso al database e deve usare query parametrizzate. In questo modo validazione, query e transazione rimangono separati.

@staticmethod non aggiunge automaticamente self alla chiamata. Se lo inserisci comunque nella firma, la chiamata Classe.metodo(2, 3) richiede un argomento in più e produce un errore. Se la funzione non usa l’istanza, bisogna rimuovere self; se invece serve lo stato dell’oggetto, è più adatto un metodo di istanza.

Valuta l'articolo

Valutazione: 0.00 Numero di voti: 0

Tag:

python metodi statici decoratori validazione dati query parametrizzate

Condividi post

Anastasio Longo

Anastasio Longo

Il mio nome è Anastasio e nel campo dell'informatica, dell'intelligenza artificiale e delle soluzioni cloud ho maturato un'esperienza di 11 anni. Fin da quando ho iniziato a esplorare questi settori, sono rimasto affascinato dal potenziale trasformativo della tecnologia e dalla sua capacità di risolvere problemi complessi. Il mio obiettivo è rendere accessibili concetti che possono sembrare ostici, analizzando le tendenze emergenti e verificando le informazioni per offrire contenuti chiari, accurati e utili. Su bartolomeoalberico.it mi dedico a spiegare come l'AI e il cloud stiano plasmando il nostro futuro, cercando sempre di organizzare la conoscenza in modo che sia facilmente comprensibile per tutti.

Scrivi un commento