eistono dei metodi speciali li riconosci dalle due __
sono metodi non vengono chiamati direttamente dal programmatore ma vengono invocati da Python in situazioni particolari

metodi:stringa
in pratica é possibile in una classe/oggetto decidere il formato in cui vengono gestite le variabili e come saranno visualizzate come stringa o come debug


esempio: creo un a classe persona con nome e cognome e poi uso i metodi
class Person: definiamo una classe Person

def __init__(self, name, surname):# definiamo costruttore un __init__ che assegna nome e cognome all'istanza
self.name = name
self.surname = surname


def __str__(self): # definiamo uno __str__ che restituisce nome e cognome a tutti i metordi stringa
return '{} {}'.format(self.name, self.surname)


def __repr__(self): # definiamo uno __repr__ che restituisce il tipo dell'istanza per devug
return '<Person object ({} {})>'.format(self.name, self.surname)


p = Person('Mario', 'Rossi') # creiamo un'istanza di Person


# l'interprete stampa automaticamente il repr() dell'oggetto
# e il metodo p.__repr__() viene invocato
p
'<Person object (Mario Rossi)>'

repr(p)
'<Person object (Mario Rossi)>'


# se usiamo str() o print() o format(), p.__str__() viene chiamato
# automaticamente e il nome completo viene restituito
str(p)
'Mario Rossi'

print(p)
Mario Rossi

'Welcome {}!'.format(p)
'Welcome Mario Rossi!'