Implémentation de la méthode __repr__
En plus de __str__, Python fournit une autre méthode spéciale pour la représentation sous forme de chaîne de caractères : __repr__. Alors que __str__ est destiné à fournir une représentation lisible par l'homme, __repr__ est destiné à fournir une représentation non ambiguë d'un objet qui peut être utilisée pour recréer l'objet si possible.
Comprendre la méthode __repr__
La méthode __repr__ est appelée lorsque vous utilisez la fonction repr() sur un objet ou lorsque vous affichez un objet dans une session interactive. Elle doit renvoyer une chaîne de caractères qui, lorsqu'elle est passée à eval(), créerait un objet équivalent (si possible).
Mettons à jour notre classe Book pour inclure une méthode __repr__ :
-
Ouvrez book.py dans l'éditeur.
-
Mettez à jour le code pour inclure une méthode __repr__ :
class Book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f'"{self.title}" by {self.author} ({self.pages} pages)'
def __repr__(self):
return f'Book("{self.title}", "{self.author}", {self.pages})'
## Create book objects
book1 = Book("The Great Gatsby", "F. Scott Fitzgerald", 180)
book2 = Book("To Kill a Mockingbird", "Harper Lee", 281)
## Print the books (uses __str__)
print("String representation (using __str__):")
print(book1)
print(book2)
## Get the representation (uses __repr__)
print("\nRepresentation (using __repr__):")
print(repr(book1))
print(repr(book2))
-
Enregistrez le fichier.
-
Exécutez le script :
python3 book.py
Vous devriez voir une sortie comme :
String representation (using __str__):
"The Great Gatsby" by F. Scott Fitzgerald (180 pages)
"To Kill a Mockingbird" by Harper Lee (281 pages)
Representation (using __repr__):
Book("The Great Gatsby", "F. Scott Fitzgerald", 180)
Book("To Kill a Mockingbird", "Harper Lee", 281)
Différences entre __str__ et __repr__
Les principales différences entre __str__ et __repr__ sont :
__str__ est destiné à une sortie lisible par l'homme, tandis que __repr__ est destiné aux développeurs et au débogage.
- Si
__str__ n'est pas défini mais que __repr__ l'est, Python utilisera __repr__ comme solution de repli pour str() ou print().
__repr__ doit idéalement renvoyer une chaîne de caractères qui peut recréer l'objet lorsqu'elle est passée à eval(), bien que cela ne soit pas toujours possible ou nécessaire.
La fonction eval() avec __repr__
Lorsqu'elle est implémentée correctement, la chaîne de caractères renvoyée par __repr__ peut être utilisée avec eval() pour recréer l'objet. Voyons cela en action :
-
Créez un nouveau fichier appelé repr_eval.py :
-
Ajoutez le code suivant :
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"Point at ({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
## Create a point
p1 = Point(3, 4)
## Get the repr string
repr_str = repr(p1)
print(f"Representation: {repr_str}")
## Use eval to recreate the object
p2 = eval(repr_str)
print(f"Recreated object: {p2}")
## Verify they have the same values
print(f"p1.x = {p1.x}, p1.y = {p1.y}")
print(f"p2.x = {p2.x}, p2.y = {p2.y}")
-
Enregistrez le fichier.
-
Exécutez le script :
python3 repr_eval.py
Vous devriez voir une sortie comme :
Representation: Point(3, 4)
Recreated object: Point at (3, 4)
p1.x = 3, p1.y = 4
p2.x = 3, p2.y = 4
Cela démontre que nous pouvons recréer l'objet d'origine en utilisant la chaîne de caractères renvoyée par __repr__ et la fonction eval().
Quand utiliser chaque méthode
- Utilisez
__init__ pour configurer l'état initial de vos objets.
- Utilisez
__str__ pour fournir une représentation lisible par l'homme pour les utilisateurs finaux.
- Utilisez
__repr__ pour fournir une représentation précise et non ambiguë pour les développeurs et le débogage.
Exercice pratique : Un exemple complet
Regroupons le tout en créant une classe Rectangle avec les trois méthodes spéciales :
-
Créez un nouveau fichier appelé rectangle.py :
-
Ajoutez le code suivant :
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
def __str__(self):
return f"Rectangle with width {self.width} and height {self.height}"
def __repr__(self):
return f"Rectangle({self.width}, {self.height})"
## Create rectangles
rect1 = Rectangle(5, 10)
rect2 = Rectangle(3, 7)
## Display information about the rectangles
print(f"Rectangle 1: {rect1}")
print(f"Area: {rect1.area()}")
print(f"Perimeter: {rect1.perimeter()}")
print(f"Representation: {repr(rect1)}")
print("\nRectangle 2: {0}".format(rect2))
print(f"Area: {rect2.area()}")
print(f"Perimeter: {rect2.perimeter()}")
print(f"Representation: {repr(rect2)}")
## Recreate a rectangle using eval
rect3 = eval(repr(rect1))
print(f"\nRecreated rectangle: {rect3}")
print(f"Is it the same area? {rect3.area() == rect1.area()}")
-
Enregistrez le fichier.
-
Exécutez le script :
python3 rectangle.py
Vous devriez voir une sortie comme :
Rectangle 1: Rectangle with width 5 and height 10
Area: 50
Perimeter: 30
Representation: Rectangle(5, 10)
Rectangle 2: Rectangle with width 3 and height 7
Area: 21
Perimeter: 20
Representation: Rectangle(3, 7)
Recreated rectangle: Rectangle with width 5 and height 10
Is it the same area? True
Cet exemple démontre comment les trois méthodes spéciales (__init__, __str__ et __repr__) fonctionnent ensemble pour créer une classe bien conçue.