Introduction
Les fonctionnalités de programmation orientée objet (POO) de Python offrent des outils puissants pour créer des objets expressifs et personnalisés. Parmi ceux-ci, les méthodes spéciales __init__, __str__ et __repr__ jouent des rôles cruciaux dans la définition du comportement et de la représentation de vos objets Python.
Dans ce tutoriel, nous allons explorer ces méthodes spéciales, comprendre leurs objectifs et apprendre à les implémenter efficacement dans vos classes Python. À la fin de ce lab, vous serez capable de créer des objets Python plus intuitifs et conviviaux.
Création de classes avec la méthode __init__
La première méthode spéciale que nous allons explorer est __init__, qui est appelée lorsqu'un objet est créé. Cette méthode vous permet d'initialiser les attributs de votre objet.
Comprendre la méthode __init__
La méthode __init__, également connue sous le nom de constructeur, est automatiquement appelée lorsque vous créez une nouvelle instance d'une classe. Son objectif principal est de configurer l'état initial de l'objet en affectant des valeurs aux attributs.
Commençons par créer une classe Python simple avec la méthode __init__ :
Ouvrez le terminal dans votre environnement LabEx.
Naviguez vers le répertoire du projet :
cd ~/projectCréez un nouveau fichier Python appelé
person.pyen utilisant l'éditeur de code :Dans l'éditeur, ajoutez le code suivant à
person.py:class Person: def __init__(self, name, age): self.name = name self.age = age ## Create a Person object person1 = Person("Alice", 30) ## Access the attributes print(f"Name: {person1.name}") print(f"Age: {person1.age}")Enregistrez le fichier.
Exécutez le script Python :
python3 person.py
Vous devriez voir la sortie suivante :
Name: Alice
Age: 30
Explication de la méthode __init__
Dans le code ci-dessus :
- Nous avons défini une classe
Personavec une méthode__init__qui prend trois paramètres :self,nameetage. - Le paramètre
selffait référence à l'instance en cours de création et est automatiquement passé lorsqu'un objet est créé. - À l'intérieur de la méthode
__init__, nous affectons les valeurs denameetageaux attributs de l'objet en utilisantself.nameetself.age. - Lorsque nous créons un nouvel objet
Personavecperson1 = Person("Alice", 30), la méthode__init__est automatiquement appelée. - Nous pouvons ensuite accéder aux attributs en utilisant la notation pointée :
person1.nameetperson1.age.
Ajout de fonctionnalités supplémentaires
Améliorons notre classe Person en ajoutant une méthode pour calculer l'année de naissance en fonction de l'année en cours et de l'âge de la personne :
Ouvrez
person.pydans l'éditeur.Mettez à jour le code pour inclure une méthode de calcul de l'année de naissance :
import datetime class Person: def __init__(self, name, age): self.name = name self.age = age def birth_year(self): current_year = datetime.datetime.now().year return current_year - self.age ## Create a Person object person1 = Person("Alice", 30) ## Access the attributes and call the method print(f"Name: {person1.name}") print(f"Age: {person1.age}") print(f"Birth Year: {person1.birth_year()}")Enregistrez le fichier.
Exécutez le script Python :
python3 person.py
La sortie devrait maintenant inclure l'année de naissance calculée :
Name: Alice
Age: 30
Birth Year: 1993
(L'année de naissance réelle dépendra de l'année en cours lorsque vous exécuterez le script)
Vous avez maintenant créé une classe Python avec la méthode __init__ pour initialiser les attributs de l'objet et ajouté une méthode pour effectuer des calculs basés sur ces attributs.
Implémentation de la méthode __str__
Maintenant que nous comprenons comment créer une classe avec la méthode __init__, explorons une autre méthode spéciale appelée __str__. Cette méthode nous permet de définir comment un objet doit être représenté sous forme de chaîne de caractères.
Comprendre la méthode __str__
La méthode __str__ est appelée lorsque vous utilisez la fonction str() sur un objet ou lorsque vous imprimez un objet en utilisant la fonction print(). Elle doit renvoyer une représentation sous forme de chaîne de caractères lisible par l'homme de l'objet.
Mettons à jour notre classe Person pour inclure une méthode __str__ :
Ouvrez
person.pydans l'éditeur.Mettez à jour le code pour inclure une méthode
__str__:import datetime class Person: def __init__(self, name, age): self.name = name self.age = age def birth_year(self): current_year = datetime.datetime.now().year return current_year - self.age def __str__(self): return f"{self.name}, {self.age} years old" ## Create a Person object person1 = Person("Alice", 30) ## Access the attributes and call the method print(f"Name: {person1.name}") print(f"Age: {person1.age}") print(f"Birth Year: {person1.birth_year()}") ## Use the __str__ method implicitly print("\nString representation of the object:") print(person1) ## Use the __str__ method explicitly print("\nExplicit string conversion:") print(str(person1))Enregistrez le fichier.
Exécutez le script Python :
python3 person.py
Vous devriez voir une sortie similaire à celle-ci :
Name: Alice
Age: 30
Birth Year: 1993
String representation of the object:
Alice, 30 years old
Explicit string conversion:
Alice, 30 years old
Comment fonctionne __str__
Dans le code ci-dessus :
- Nous avons défini une méthode
__str__qui renvoie une chaîne formatée avec le nom et l'âge de la personne. - Lorsque nous appelons
print(person1), Python appelle automatiquement la méthode__str__pour déterminer ce qu'il faut afficher. - Nous pouvons également convertir explicitement un objet en chaîne de caractères en utilisant
str(person1), ce qui appelle également la méthode__str__.
Que se passe-t-il sans __str__
Pour comprendre l'importance de la méthode __str__, voyons ce qui se passe lorsque nous ne la définissons pas :
Créez un nouveau fichier appelé
without_str.py:Ajoutez le code suivant :
class SimpleClass: def __init__(self, value): self.value = value ## Create an object obj = SimpleClass(42) ## Print the object print(obj)Enregistrez le fichier.
Exécutez le script :
python3 without_str.py
Vous devriez voir une sortie comme :
<__main__.SimpleClass object at 0x7f2d8c3e9d90>
La sortie n'est pas très informative. Elle affiche le nom de la classe et l'adresse mémoire de l'objet, mais pas son contenu. C'est pourquoi l'implémentation d'une méthode __str__ appropriée est importante pour rendre vos objets plus conviviaux.
Exercice pratique
Créons une nouvelle classe appelée Book avec une méthode __str__ :
Créez un nouveau fichier appelé
book.py:Ajoutez le code suivant :
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)' ## Create book objects book1 = Book("The Great Gatsby", "F. Scott Fitzgerald", 180) book2 = Book("To Kill a Mockingbird", "Harper Lee", 281) ## Print the books print(book1) print(book2)Enregistrez le fichier.
Exécutez le script :
python3 book.py
La sortie devrait être :
"The Great Gatsby" by F. Scott Fitzgerald (180 pages)
"To Kill a Mockingbird" by Harper Lee (281 pages)
Vous comprenez maintenant comment utiliser la méthode __str__ pour créer des représentations sous forme de chaîne de caractères lisibles par l'homme de vos objets.
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.pydans 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 pourstr()ouprint(). __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.
Création d'une application pratique
Maintenant que nous comprenons les trois méthodes spéciales __init__, __str__ et __repr__, créons une application plus pratique qui démontre leur utilisation dans un scénario réel. Nous allons créer un système bancaire simple avec une classe BankAccount.
Construction d'une classe Bank Account
Créez un nouveau fichier appelé
bank_account.py:Ajoutez le code suivant :
class BankAccount: def __init__(self, account_number, owner_name, balance=0.0): self.account_number = account_number self.owner_name = owner_name self.balance = balance self.transactions = [] def deposit(self, amount): if amount <= 0: print("Deposit amount must be positive") return False self.balance += amount self.transactions.append(f"Deposit: +${amount:.2f}") return True def withdraw(self, amount): if amount <= 0: print("Withdrawal amount must be positive") return False if amount > self.balance: print("Insufficient funds") return False self.balance -= amount self.transactions.append(f"Withdrawal: -${amount:.2f}") return True def get_transaction_history(self): return self.transactions def __str__(self): return f"Account {self.account_number} | Owner: {self.owner_name} | Balance: ${self.balance:.2f}" def __repr__(self): return f'BankAccount("{self.account_number}", "{self.owner_name}", {self.balance})'Enregistrez le fichier.
Test de la classe Bank Account
Testons maintenant notre classe BankAccount :
Créez un nouveau fichier appelé
bank_test.py:Ajoutez le code suivant :
from bank_account import BankAccount ## Create bank accounts account1 = BankAccount("12345", "John Doe", 1000.0) account2 = BankAccount("67890", "Jane Smith", 500.0) ## Display initial account information print("Initial Account Status:") print(account1) print(account2) ## Perform transactions print("\nPerforming transactions...") ## Deposit to account1 print("\nDepositing $250 to account1:") account1.deposit(250) print(account1) ## Withdraw from account2 print("\nWithdrawing $100 from account2:") account2.withdraw(100) print(account2) ## Try to withdraw too much from account2 print("\nTrying to withdraw $1000 from account2:") account2.withdraw(1000) print(account2) ## Try to deposit a negative amount to account1 print("\nTrying to deposit -$50 to account1:") account1.deposit(-50) print(account1) ## Display transaction history print("\nTransaction history for account1:") for transaction in account1.get_transaction_history(): print(f"- {transaction}") print("\nTransaction history for account2:") for transaction in account2.get_transaction_history(): print(f"- {transaction}") ## Recreate an account using repr print("\nRecreating account1 using repr:") account1_repr = repr(account1) print(f"Representation: {account1_repr}") recreated_account = eval(account1_repr) print(f"Recreated account: {recreated_account}")Enregistrez le fichier.
Exécutez le script :
python3 bank_test.py
Vous devriez voir une sortie similaire à celle-ci :
Initial Account Status:
Account 12345 | Owner: John Doe | Balance: $1000.00
Account 67890 | Owner: Jane Smith | Balance: $500.00
Performing transactions...
Depositing $250 to account1:
Account 12345 | Owner: John Doe | Balance: $1250.00
Withdrawing $100 from account2:
Account 67890 | Owner: Jane Smith | Balance: $400.00
Trying to withdraw $1000 from account2:
Insufficient funds
Account 67890 | Owner: Jane Smith | Balance: $400.00
Trying to deposit -$50 to account1:
Deposit amount must be positive
Account 12345 | Owner: John Doe | Balance: $1250.00
Transaction history for account1:
- Deposit: +$250.00
Transaction history for account2:
- Withdrawal: -$100.00
Recreating account1 using repr:
Representation: BankAccount("12345", "John Doe", 1250.0)
Recreated account: Account 12345 | Owner: John Doe | Balance: $1250.00
Comprendre l'implémentation
Dans cette application bancaire :
La méthode
__init__initialise un compte bancaire avec un numéro de compte, le nom du propriétaire et un solde initial facultatif. Elle crée également une liste vide pour suivre les transactions.Les méthodes
depositetwithdrawgèrent les transactions et mettent à jour le solde et l'historique des transactions.La méthode
__str__fournit une représentation conviviale du compte, affichant le numéro de compte, le nom du propriétaire et le solde actuel.La méthode
__repr__fournit une chaîne de caractères qui peut recréer l'objet compte (bien que l'historique des transactions ne soit pas conservé dans cette implémentation).
Cet exemple démontre comment ces méthodes spéciales peuvent être utilisées dans une application pratique pour créer des objets plus intuitifs et conviviaux.
Extension de l'application
En guise d'exercice final, créons un système bancaire simple qui gère plusieurs comptes :
Créez un nouveau fichier appelé
banking_system.py:Ajoutez le code suivant :
from bank_account import BankAccount class BankingSystem: def __init__(self, bank_name): self.bank_name = bank_name self.accounts = {} def create_account(self, account_number, owner_name, initial_balance=0.0): if account_number in self.accounts: print(f"Account {account_number} already exists") return None account = BankAccount(account_number, owner_name, initial_balance) self.accounts[account_number] = account return account def get_account(self, account_number): return self.accounts.get(account_number) def list_accounts(self): return list(self.accounts.values()) def __str__(self): return f"{self.bank_name} - Managing {len(self.accounts)} accounts" def __repr__(self): return f'BankingSystem("{self.bank_name}")' ## Create a banking system bank = BankingSystem("Python First Bank") print(bank) ## Create some accounts bank.create_account("A001", "John Doe", 1000) bank.create_account("A002", "Jane Smith", 500) bank.create_account("A003", "Bob Johnson", 250) ## List all accounts print("\nAll accounts:") for account in bank.list_accounts(): print(account) ## Make some transactions account = bank.get_account("A001") if account: print(f"\nBefore deposit: {account}") account.deposit(500) print(f"After deposit: {account}") account = bank.get_account("A002") if account: print(f"\nBefore withdrawal: {account}") account.withdraw(200) print(f"After withdrawal: {account}") ## Try to create an existing account print("\nTrying to create an existing account:") bank.create_account("A001", "Someone Else", 300) ## Final state of the banking system print(f"\n{bank}")Enregistrez le fichier.
Exécutez le script :
python3 banking_system.py
Vous devriez voir une sortie similaire à :
Python First Bank - Managing 0 accounts
All accounts:
Account A001 | Owner: John Doe | Balance: $1000.00
Account A002 | Owner: Jane Smith | Balance: $500.00
Account A003 | Owner: Bob Johnson | Balance: $250.00
Before deposit: Account A001 | Owner: John Doe | Balance: $1000.00
After deposit: Account A001 | Owner: John Doe | Balance: $1500.00
Before withdrawal: Account A002 | Owner: Jane Smith | Balance: $500.00
After withdrawal: Account A002 | Owner: Jane Smith | Balance: $300.00
Trying to create an existing account:
Account A001 already exists
Python First Bank - Managing 3 accounts
Cet exemple démontre comment utiliser la classe BankAccount que nous avons créée précédemment dans une application plus complète. Il montre comment les méthodes spéciales __init__, __str__ et __repr__ fournissent une base solide pour la création de classes intuitives et conviviales.
Résumé
Dans ce laboratoire, vous avez appris trois méthodes spéciales essentielles en Python qui vous aident à créer des objets plus expressifs et conviviaux :
__init__: La méthode constructeur qui initialise les attributs d'un objet lors de sa création.__str__: Une méthode qui fournit une représentation sous forme de chaîne de caractères lisible par l'homme d'un objet, principalement pour les utilisateurs finaux.__repr__: Une méthode qui fournit une représentation sous forme de chaîne de caractères non ambiguë d'un objet, principalement pour les développeurs et le débogage.
Vous avez implémenté ces méthodes dans plusieurs exemples, allant de classes simples comme Person et Book à des applications plus complexes comme un système bancaire. Vous avez également appris les différences entre __str__ et __repr__ et quand utiliser chacune d'elles.
En maîtrisant ces méthodes spéciales, vous pouvez créer des objets Python plus intuitifs et personnalisés qui s'intègrent de manière transparente aux fonctionnalités intégrées du langage. Ces connaissances constituent une partie essentielle de la programmation orientée objet en Python et vous aideront à écrire un code plus propre et plus facile à maintenir.
Au fur et à mesure que vous poursuivez votre parcours Python, rappelez-vous qu'il existe de nombreuses autres méthodes spéciales disponibles qui vous permettent de personnaliser davantage le comportement de vos objets. Explorer ces méthodes vous donnera encore plus de contrôle sur la façon dont vos objets se comportent dans différents contextes.



