Qu'est-ce que __init__ en Python ? [With Examples]
Initiation à la conception orientée objet avec la méthode __init__ en Python
Souhaitez-vous vous lancer dans le développement orienté objet en Python ? Commencez dès maintenant en explorant la méthode fondamentale __init__.
Dans ce guide, nous allons détailler les bases des classes et des objets en Python, puis nous examinerons de près la méthode __init__.
À la fin de ce tutoriel, vous serez capable de répondre aux questions clés suivantes :
- Qu'est-ce que les variables d'instance, également appelées attributs d'instance ?
- Comment la méthode init facilite-t-elle l'initialisation de ces attributs d'instance ?
- Comment définir des valeurs par défaut pour les attributs lors de leur initialisation ?
- Comment les méthodes de classe peuvent-elles agir comme constructeurs d'objets ?
Commençons sans plus tarder.
Classes et objets en Python : Les Fondamentaux
Les classes sont des éléments essentiels de la programmation orientée objet en Python. Elles permettent de définir des structures de données personnalisées, regroupant à la fois des données (attributs) et les opérations (méthodes) qui leur sont associées.
Une fois une classe définie, nous pouvons l'utiliser comme un modèle pour créer des objets, qui sont des instances concrètes de cette classe.
Prenons un exemple concret : imaginons une classe `Employé` où chaque objet (instance) posséderait les attributs suivants :
- `nom_complet` : le nom complet de l'employé au format prénom nom.
- `id_employe` : l'identifiant unique de l'employé.
- `departement` : le service auquel l'employé est rattaché.
- `experience` : le nombre d'années d'expérience de l'employé.
Chaque employé est un objet de la classe `Employé`, et chaque objet possède ses propres valeurs pour les attributs `nom_complet`, `id_employe`, `departement`, et `experience`.
Ces attributs sont aussi appelés variables d'instance, et les termes "attribut" et "variable d'instance" seront utilisés de manière interchangeable dans ce guide.

Nous allons maintenant voir comment ajouter des attributs, mais pour le moment, créons simplement une classe `Employé` vide :
class Employee:
pass
L'instruction `pass` est utilisée comme un espace réservé pour éviter les erreurs lors de l'exécution du code, si la classe n'a pas de contenu pour le moment.
Même si cette version de la classe `Employé` n'est pas très utile, elle est parfaitement valide. Nous pouvons donc créer des objets de cette classe :
employee_1 = Employee() print(employee_1) #Output: <__main__.Employee object at 0x00FEE7F0>
Il est également possible d'ajouter et d'initialiser les attributs d'un objet directement comme ceci :
employee_1.full_name="Amy Bell" employee_1.department="HR"
Cependant, cette méthode d'ajout d'attributs est à la fois inefficace et source d'erreurs. Elle ne permet pas d'utiliser la classe comme un modèle de création d'objets. C'est là que la méthode `__init__` entre en jeu.
Le Rôle Essentiel de la Méthode __init__ en Python

La méthode `__init__` permet d'initialiser les variables d'instance lors de la création d'un nouvel objet. Elle est automatiquement appelée à chaque fois qu'un nouvel objet de la classe est créé pour initialiser les valeurs de ses attributs.
Si vous êtes familier avec d'autres langages comme C++, vous constaterez que la méthode `__init__` joue un rôle similaire à celui des constructeurs.
Définition de la méthode __init__
Ajoutons maintenant la méthode `__init__` à notre classe `Employé` :
class Employee:
def __init__(self, full_name,emp_id,department,experience):
self.full_name = full_name
self.emp_id = emp_id
self.department = department
self.experience = experience
Le paramètre `self` fait référence à l'instance de la classe. L'expression `self.attribut` initialise l'attribut d'instance avec la valeur correspondante fournie.
Nous pouvons désormais créer des objets en fournissant les valeurs des attributs :
employee_2 = Employee('Bella Joy','M007','Marketing',3)
print(employee_2)
# Output: <__main__.Employee object at 0x017F88B0>
Lorsque nous affichons l'objet `employee_2`, nous n'obtenons pas beaucoup d'informations utiles. Pour remédier à cela, ajoutons une méthode `__repr__`, qui définit la représentation sous forme de chaîne de caractères de notre classe :
def __repr__(self):
return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."
En ajoutant cette méthode à notre classe, nous obtenons :
class Employee:
def __init__(self, full_name,emp_id,department,experience):
self.full_name = full_name
self.emp_id = emp_id
self.department = department
self.experience = experience
def __repr__(self):
return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."
Maintenant, les objets `Employé` ont une représentation sous forme de chaîne plus informative :
print(employee_2) # Output: Bella Joy,M007 from Marketing with 3 years of experience.
Quelques conventions à respecter
Avant de continuer, voici quelques points importants :
- Nous utilisons généralement le paramètre `self` comme premier argument de la méthode `__init__` pour faire référence à l'instance de la classe elle-même. Le nom `self` est une convention largement adoptée (mais vous pouvez utiliser un autre nom).
- Pour plus de clarté et de lisibilité, nous choisissons de nommer les paramètres de la méthode `__init__` de la même manière que les attributs d'instance.
Définir des Valeurs par Défaut pour les Attributs

Jusqu'à présent, nous avons vu que tous les attributs sont obligatoires. La création d'un objet n'aboutit que si l'on fournit des valeurs pour tous les champs à la méthode `__init__`.
Si l'on tente de créer un objet de la classe `Employé` sans fournir la valeur de l'attribut `experience` :
employee_3 = Employee('Jake Lee','E001','Engineering')
On obtient l'erreur suivante :
Traceback (most recent call last):
File "main.py", line 22, in <module>
employee_3 = Employee('Jake Lee','E001','Engineering')
TypeError: __init__() missing 1 required positional argument: 'experience'
Pour rendre certains attributs optionnels, nous pouvons leur attribuer des valeurs par défaut lors de la définition de la méthode `__init__`.
Ici, nous assignons la valeur par défaut 0 à l'attribut `experience` :
class Employee:
def __init__(self, full_name,emp_id,department,experience=0):
self.full_name = full_name
self.emp_id = emp_id
self.department = department
self.experience = experience
def __repr__(self):
return f"{self.full_name},{self.emp_id} from {self.department} with {self.experience} years of experience."
L'objet `employee_3` est créé sans valeur pour l'attribut `experience`, et la valeur par défaut 0 est utilisée :
employee_3 = Employee('Jake Lee','E001','Engineering')
print(employee_3.experience)
# Output: 0
Constructeurs Alternatifs : Utilisation de Méthodes de Classe

Jusqu'à présent, nous avons exploré comment définir la méthode `__init__` et comment définir des valeurs par défaut pour les attributs. Il faut cependant fournir des valeurs pour les attributs nécessaires.
Parfois, les valeurs de ces variables d'instance peuvent être disponibles dans une structure de données différente, comme un tuple, un dictionnaire ou un objet JSON.
Comment traiter ces situations ?
Prenons un exemple où les valeurs des attributs sont stockées dans un dictionnaire Python :
dict_fanny = {'name':'Fanny Walker','id':'H203','dept':'HR','exp':2}
Nous pourrions accéder aux valeurs des attributs du dictionnaire comme ceci :
name = dict_fanny['name'] id = dict_fanny['id'] dept = dict_fanny['dept'] exp = dict_fanny['exp']
Ensuite, nous pourrions créer un objet en utilisant ces valeurs :
employee_4 = Employee(name, id, dept, exp) print(employee_4) # Output: Fanny Walker,H203 from HR with 2 years of experience.
Mais il faut répéter ce processus pour chaque nouvel objet, ce qui n'est pas très efficace. Heureusement, nous pouvons faire mieux.
En Python, nous pouvons utiliser des méthodes de classe comme constructeurs d'objets. Pour définir une méthode de classe, on utilise le décorateur `@classmethod`.
Définissons une méthode qui récupère les valeurs des variables d'instance depuis un dictionnaire et crée un objet `Employé` :
@classmethod
def from_dict(cls,data_dict):
full_name = data_dict['name']
emp_id = data_dict['id']
department = data_dict['dept']
experience = data_dict['exp']
return cls(full_name, emp_id, department, experience)
Désormais, pour créer un objet à partir des données d'un dictionnaire, nous pouvons utiliser la méthode de classe `from_dict()`.
💡 Notez l'utilisation de `cls` dans la méthode de classe au lieu de `self`. Tout comme `self` fait référence à l'instance, `cls` fait référence à la classe. Les méthodes de classe sont liées à la classe, et non à ses objets.
Ainsi, lorsque nous appelons la méthode de classe `from_dict()` pour créer des objets, nous l'appelons sur la classe `Employé` :
emp_dict = {'name':'Tia Bell','id':'S270','dept':'Sales','exp':3}
employee_5 = Employee.from_dict(emp_dict)
print(employee_5)
# Output: Tia Bell,S270 from Sales with 3 years of experience.
Maintenant, si nous avons un dictionnaire pour chacun des employés, nous pouvons utiliser la méthode de classe `from_dict()` comme constructeur, sans avoir à récupérer manuellement les valeurs des attributs du dictionnaire.
📝 Note sur les variables de classe
Nous avons défini une méthode de classe qui est liée à la classe, et non aux instances individuelles. De la même manière, nous pouvons avoir des variables de classe.
Les variables de classe sont également liées à la classe et non aux instances. Lorsqu'un attribut doit avoir une valeur fixe pour toutes les instances d'une classe, il est préférable de le définir comme une variable de classe.
FAQ
1. Pourquoi est-il nécessaire d'utiliser la méthode `__init__` en Python ?
La méthode `__init__` permet d'initialiser les attributs d'instance de chaque objet de la classe. Elle est appelée automatiquement chaque fois qu'une nouvelle instance de la classe est créée.
2. Peut-on avoir plusieurs méthodes `__init__` dans une classe Python ?
L'objectif d'avoir plusieurs méthodes `__init__` serait de fournir plusieurs constructeurs. Cependant, il n'est pas possible de définir plusieurs méthodes `__init__`. Si vous le faites, la dernière définition remplacera toutes les précédentes. La solution est d'utiliser le décorateur `@classmethod` pour définir des méthodes de classe qui serviront de constructeurs d'objets.
3. Que se passe-t-il si l'on ne définit pas de méthode `__init__` dans une classe ?
Il est toujours possible de créer des objets, mais vous devrez ajouter manuellement les variables d'instance et leur assigner des valeurs. Vous ne pourrez pas non plus passer de valeurs à la construction de l'objet. Cette méthode est source d'erreurs et ne permet pas d'utiliser les classes comme des modèles de création d'objets.
4. Peut-on définir des valeurs par défaut pour les arguments de la méthode `__init__` ?
Oui, il est tout à fait possible de définir des valeurs par défaut pour un ou plusieurs attributs. Cela rend ces attributs optionnels lors de la construction de l'objet. Les attributs prendront les valeurs par défaut si vous ne spécifiez pas de valeurs lors de la création de l'objet.
5. Peut-on modifier des attributs en dehors de la méthode `__init__` ?
Oui, il est tout à fait possible de modifier la valeur d'un attribut après la création de l'objet. Vous pouvez également ajouter dynamiquement de nouveaux attributs à une instance après sa création.
Conclusion
Dans ce guide, nous avons appris à utiliser la méthode `__init__` pour initialiser les valeurs des variables d'instance. C'est un outil très simple, mais cela peut être répétitif, surtout si vous avez de nombreux attributs.
Si cela vous intéresse, vous pouvez explorer le module `dataclasses`. Dans les versions de Python 3.7 et supérieures, vous pouvez utiliser le module intégré des classes de données pour créer des classes de données qui stockent des données. Il offre des implémentations par défaut de `__init__` et d'autres méthodes couramment utilisées, ainsi que des fonctionnalités intéressantes pour les annotations de types, les valeurs par défaut complexes et les optimisations.
Pour continuer votre apprentissage, vous pouvez maintenant vous intéresser à l'utilisation de `if __name__ == '__main__'` en Python.