Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Metodi speciali

Quando si definisce una classe in Python, è possibile usare diversi metodi speciali, quali __str__, __repr__, __bool__ e __len__: ecco a cosa servono.
Quando si definisce una classe in Python, è possibile usare diversi metodi speciali, quali __str__, __repr__, __bool__ e __len__: ecco a cosa servono.
Link copiato negli appunti

Nelle lezioni precedenti abbiamo visto che esistono diversi metodi "speciali", indicati dalla presenza di due underscore prima e dopo il nome (ad esempio, __metodo__). Questi metodi non vengono chiamati direttamente dal programmatore, ma vengono invocati da Python in situazioni particolari. Parlando delle classi, ad esempio, abbiamo incontrato il metodo speciale __init__, invocato automaticamente durante la creazione delle istanze. In questa lezione vedremo altri metodi speciali e come possono essi possano essere utili in vari contesti.

__str__ e __repr__

Oltre all'__init__, ci sono altri due metodi speciali che vengono comunemente aggiunti quando si definisce una nuova classe: __str__ e __repr__. Questi due metodi vengono invocati automaticamente quando eseguiamo str(istanza) e repr(istanza), o quando chiamiamo funzioni che eseguono queste operazioni (ad esempio: print(istanza)).

Entrambi i metodi devono restituire una stringa: la differenza è che __str__ restituisce un valore utile all'utente, mentre __repr__ un valore utile allo sviluppatore:

>>> # definiamo una classe Person
>>> class Person:
... # definiamo un __init__ che assegna nome e cognome all'istanza
... def __init__(self, name, surname):
... self.name = name
... self.surname = surname
... # definiamo uno __str__ che restituisce nome e cognome
... def __str__(self):
... return '{} {}'.format(self.name, self.surname)
... # definiamo uno __repr__ che restituisce il tipo dell'istanza
... def __repr__(self):
... return '<Person object ({} {})>'.format(self.name, self.surname)
...
>>> # creiamo un'istanza di Person
>>> p = Person('Ezio', 'Melotti')
>>> # l'interprete stampa automaticamente il repr() dell'oggetto
>>> # e il metodo p.__repr__() viene invocato
>>> p
'<Person object (Ezio Melotti)>'
>>> repr(p)
'<Person object (Ezio Melotti)>'
>>> # se usiamo str(), print(), o format(), p.__str__() viene chiamato
>>> # automaticamente e il nome completo viene restituito
>>> str(p)
'Ezio Melotti'
>>> print(p)
Ezio Melotti
>>> 'Welcome {}!'.format(p)
'Welcome Ezio Melotti!'

Da questo esempio possiamo vedere che il __repr__ contiene informazioni utili allo sviluppatore, come il il tipo dell'oggetto e il valore degli attributi name e surname, mentre il valore restituito da __str__ include solo il nome e il cognome, e può essere usato direttamente in un'interfaccia utente o in messaggi generati mediante la funzione print.

Il valore restituito da __repr__ può contenere più o meno informazioni, ma in genere è bene che rispetti una delle seguenti due forme:

  • <Classe object ...>: il nome della classe seguita da informazioni aggiuntive (ad esempio il valore di alcuni attributi), il tutto racchiuso tra <...> (es.
    <Person object: name='Ezio' surname='Melotti'>
    ).
  • Classe(arg1, arg2, ..., argN): l'espressione usata per creare l'istanza, in grado di dirci il nome della classe e il valore degli attributi (es. Person('Ezio', 'Melotti')).

__bool__ e __len__

Il metodo speciale __bool__ può essere usato per definire se un oggetto è vero o falso, mentre il metodo __len__ può ritornare la lunghezza (o il numero di elementi) di un oggetto.

Se __bool__ non è definito, Python può usare il risultato di __len__ per determinare se un oggetto è vero o falso (una lunghezza diversa da 0 è considerata vera). Se anche __len__ non è definito, l'oggetto è considerato vero.

>>> # definiamo una classe Team
>>> class Team:
... # definiamo un __init__ che assegna i membri all'istanza
... def __init__(self, members):
... self.members = members
... # definiamo un __bool__ che restituisce False se il
... # team ha 0 membri, altrimenti True
... def __bool__(self):
... return len(self.members) > 0
... # definiamo un __len__ che restituisce il numero di membri
... def __len__(self):
... return len(self.members)
... # definiamo un __repr__ che restituisce il tipo dell'oggetto
... # e i nomi dei membri del team
... def __repr__(self):
... names = ', '.join([p.name for p in self.members])
... return '<Team object [{}]>'.format(names)
...
>>> # creiamo un'istanza di Team con 3 membri
>>> t1 = Team([Person('Guido', 'van Rossum'),
... Person('Alex', 'Martelli'),
... Person('Ezio', 'Melotti'),])
>>> # verifichiamo il repr dell'oggetto
>>> t1
<Team object [Guido, Alex, Ezio]>
>>> # verifichiamo che il team ha 3 membri
>>> t1.members
[<Person object (Guido van Rossum)>,
<Person object (Alex Martelli)>,
<Person object (Ezio Melotti)>]
>>> # verifichiamo che la lunghezza del team è 3
>>> len(t1)
3
>>> # verifichiamo che questo team è considerato "vero"
>>> bool(t1)
True
>>>
>>> # creiamo un'altra istanza di Team con 0 membri
>>> t2 = Team([])
>>> # verifichiamo il repr dell'oggetto
>>> t2
<Team object []>
>>> # verifichiamo che il team ha 0 membri
>>> t2.members
[]
>>> # verifichiamo che la lunghezza del team è 0
>>> len(t2)
0
>>> # verifichiamo che questo team è considerato "falso"
>>> bool(t2)
False

Nell'esempio, abbiamo definito una classe Team che include una lista di membri. Quando usiamo len(istanza), viene automaticamente invocato il metodo Team.__len__(), che ci restituisce il numero di membri nel team. Quando usiamo bool(istanza) o if istanza: ..., viene invece invocato il metodo Team.__bool__(), che ci restituisce True se il team ha almeno un membro, altrimenti False.

Ti consigliamo anche