What’s in a name? That which we call a rose
by any other name would smell as sweet.
William Shakespeare, Romeo e Giulietta
Alla fine della scorsa lezione ti ho lasciato con un fastidio. Ogni volta che vogliamo mostrare un brano scriviamo a mano la stessa f-string: print(f"{bohemian.titolo} — {bohemian.artista}"). È ripetitivo, è facile sbagliarlo, e soprattutto è strano: l’oggetto sa tutto di sé — titolo, artista, durata — eppure tocca a noi, da fuori, ricostruirgli la frase ogni volta.
E se fosse il brano stesso a sapersi raccontare? Se potessimo scrivere semplicemente print(bohemian) e ottenere una descrizione sensata? Oggi insegniamo all’oggetto a presentarsi da solo. Lo faremo incontrando i primi due metodi speciali di Python — quelli con il doppio trattino basso ai lati, i cosiddetti dunder — di cui in realtà ne hai già usato uno senza farci caso: __init__.
Partiamo da un Brano essenziale, senza alcun metodo speciale oltre a __init__. Proviamo a stamparlo direttamente. Prima di premere Run, predici l’output: cosa comparirà?
Ti aspettavi il titolo? E invece esce qualcosa come <__main__.Brano object at 0x...>: il nome della classe e un codice esadecimale che è, in pratica, l’indirizzo dell’oggetto in memoria. Tecnicamente è una risposta — ti dice che tipo è e che è unico — ma a un essere umano non serve a niente. Python non può indovinare quale dei tre dati vuoi vedere, né come comporli: per stamparlo in modo decente, glielo dobbiamo insegnare noi.
Quando scrivi print(qualcosa), dietro le quinte Python chiama il metodo speciale __str__ di quell’oggetto e stampa ciò che restituisce. Se non l’hai definito, ripiega su quella rappresentazione tecnica di prima. Definiamolo, allora: deve restituire (non stampare!) una stringa leggibile.
Niente più indirizzi di memoria. E nota la seconda riga: anche dentro una f-string, {bohemian} passa da __str__. Lo stesso vale per str(bohemian). Da ora il brano sa dire chi è, e noi non dobbiamo più ricostruirgli la frase ogni volta: la formattazione vive dentro l’oggetto, in un posto solo. È esattamente la coesione di cui parliamo dalla prima lezione.
Mettiamo i nostri brani in una playlist — una semplice lista — e stampiamola. Abbiamo definito __str__, quindi vedremo i titoli, giusto? Predici l’output prima di eseguire.
Ricompaiono gli indirizzi di memoria — [<__main__.Brano object at 0x...>, ...] — nonostante __str__ sia definito. Cos’è successo? Quando stampi una lista, Python non chiama __str__ sui suoi elementi: chiama l’altro metodo speciale, __repr__. E quello, noi, non l’abbiamo ancora scritto.
Non è un capriccio. C’è un motivo, e ci porta dritti al secondo protagonista della lezione.
__str__ risponde a «come mostro questo oggetto a un utente?» → leggibile, discorsivo, anche incompleto.
__repr__ risponde a «come descrivo questo oggetto a chi programma?» → non ambiguo, preciso, idealmente completo.
Quando in console ispezioni una lista, un dizionario o un oggetto «da solo», sei nei panni dello sviluppatore che vuole capire esattamente cosa ha in mano: per questo Python sceglie __repr__. La convenzione è che __repr__ somigli alla chiamata del costruttore che ricrea l’oggetto. Aggiungiamolo:
Ora la lista mostra qualcosa di utile: [Brano('Bohemian Rhapsody', 'Queen', 354)]. Leggendolo capisci al volo il tipo e tutti i dati, e — colpo di scena — potresti copiarlo, incollarlo nel codice ed eseguirlo per ottenere un brano identico. Questo è il senso di «non ambiguo».
Il diagramma mostra chi chiama cosa — e quella freccia tratteggiata è la regola più importante della lezione.
I due metodi non sono obbligatori in coppia. C’è un’asimmetria voluta: se definisci solo__repr__, Python lo usa anche come ripiego quando servirebbe __str__. Il contrario non vale: definire solo __str__ lascia __repr__ con la sua versione tecnica inutile.
print(bury) non trova un __str__ e usa __repr__: ottieni comunque qualcosa di sensato. Da qui la regola pratica.
Mettiamo insieme i pezzi su una mini-playlist, con entrambi i metodi e una distinzione netta tra i due usi. Cambia i dati, aggiungi un brano, e osserva come l’una e l’altra faccia restano coerenti senza che tu debba comporre stringhe a mano da nessuna parte.
Stessa playlist, due letture: una per chi ascolta, una per chi mette le mani nel codice. È la frase di Shakespeare ribaltata in chiave informatica — il nome con cui mostri la rosa cambia a seconda di chi la guarda, ma la rosa (l’oggetto, con i suoi dati) resta la stessa.
Mettiti alla provaDomanda 1 / 3
Hai una classe Brano con __str__ definito ma senza__repr__. Cosa stampa print([brano]) (il brano dentro una lista)?
Per una classe devi scriverne uno solo tra __str__ e __repr__. Quale conviene definire e perché?
Quale di queste è una buona implementazione di __repr__ per Brano(titolo, artista, durata)?