Une instance en Python : l'objet créé à partir d'une classe

Une instance est l'objet concret fabriqué à partir d'une classe, avec ses propres valeurs en mémoire, indépendantes de celles des autres objets.
6 min de lecture
Believemy logo

Définition

Un programme manipule rarement un seul compte ou un seul utilisateur. Il en gère des dizaines, semblables par leur forme et différents par leurs valeurs. Une variable par compte devient vite intenable : à cinquante clients, personne ne s'y retrouve.

D'où la séparation entre la classe et ses instances. La classe décrit ce qu'un objet contient et sait faire, mais elle ne détient rien : c'est un plan. L'instance est l'exemplaire fabriqué à partir de ce plan, qui vit en mémoire avec ses propres valeurs. Une classe Compte ne détient l'argent de personne : c'est chaque compte ouvert qui porte un solde.

L'exemple suivant crée deux comptes à partir de cette classe, puis crédite le premier. Regardez ce qu'affiche le second.

PYTHON
class Compte:
    def __init__(self, titulaire):
        self.titulaire = titulaire   # une valeur propre à cet objet
        self.solde = 0

premier = Compte("Camille")   # une instance
second = Compte("Sofia")      # une autre, indépendante

premier.solde = 120
print(second.solde)   # 0 : le second n'a rien vu passer

Les deux comptes sortent du même plan et ne partagent pourtant rien. Créditer le premier laisse le second intact : voilà ce qui définit une instance, des valeurs bien à elle. Mille comptes peuvent coexister sans jamais se marcher dessus.


Ce qui appartient à l'instance, ce qui appartient à la classe

Reste à savoir où poser une valeur, car Python offre deux emplacements très ressemblants à la lecture. Un attribut écrit dans le corps de la classe est créé une seule fois, au chargement du fichier, et tous les objets s'y réfèrent. Un attribut posé sur self est recréé à chaque construction : il en existe autant que d'objets.

Le tableau met les deux écritures côte à côte, la dernière colonne d'abord : ce qui les sépare tient à l'usage, pas à la syntaxe.

ÉcritureOù vit la valeurConséquence
frais = 2 dans la classeSur la classeUne seule valeur pour tout le programme
self.solde = 0 dans __init__Sur l'instanceUne valeur par objet créé
historique = [] dans la classeSur la classeLa même liste pour tous les objets

La troisième ligne est le piège, invisible à la relecture. Une collection mutable déclarée au niveau de la classe est construite une seule fois, au chargement du fichier : chaque objet qui y ajoute une opération écrit chez tous les autres. Sans la moindre erreur, l'historique du premier client finit par contenir les mouvements du dernier.

Les deux lignes ci-dessous se confondent facilement, alors qu'une seule donne à chaque objet son propre historique.

PYTHON
class Compte:
    historique = []           # partagé par tous : presque toujours une erreur

    def __init__(self):
        self.historique = []  # recréé pour chaque instance : ce qu'on veut
Attention

Une liste ou un dictionnaire écrit au niveau de la classe existe en un seul exemplaire pour tout le programme, et la panne remonte bien plus tard, souvent en production. Une valeur qui change d'un objet à l'autre s'écrit sur self, dans __init__.


Ce que Python fait quand la classe est appelée

Écrire Compte("Camille") ressemble à un appel de fonction, et l'on croit volontiers que cela exécute la seule méthode d'initialisation. Il s'en passe un peu plus : __new__ fabrique l'objet vide, puis __init__ le remplit. La première étape crée l'instance, la seconde lui donne son contenu. La nuance ne se voit que sur les cas particuliers, comme un objet immuable, à préparer avant sa création.

Vient alors une autre question : comment une méthode sait-elle sur quel objet elle travaille ? Dans chaque méthode, le premier paramètre reçoit l'instance sur laquelle l'appel a été fait, et Python le passe automatiquement. C'est tout le rôle de self, simple nom de paramètre rendu universel par la convention. Appeler premier.crediter(50) revient à écrire Compte.crediter(premier, 50), forme qui rend visible ce que la première dissimule.


Vérifier qu'un objet est bien l'instance attendue

Aux frontières d'un programme arrivent des objets dont on ignore la provenance, et il faut parfois vérifier leur nature. La fonction isinstance répond à cette question et accepte les descendants : un objet issu d'une classe fille passe le test de la classe mère, là où une comparaison sur le type le refuse.

La différence compte dès qu'un héritage entre en jeu, sous peine de rejeter des objets valides. L'exemple pose les deux contrôles sur un livret, sorte de compte.

PYTHON
class Livret(Compte):
    pass

epargne = Livret("Camille")

isinstance(epargne, Compte)   # True : un livret est bien un compte
type(epargne) is Compte       # False : son type exact reste Livret

Les deux réponses sont justes : isinstance demande si l'objet sait se comporter comme un compte, type de quelle classe exacte il sort. En pratique, la première question suffit presque toujours.

Cela dit, la culture Python n'encourage pas ces contrôles. Le duck typing préfère appeler la méthode attendue et rattraper l'AttributeError si elle manque, ce qui laisse la porte ouverte à des objets d'une classe imprévue. Le test d'instance garde sa place là où arrivent des données dont la forme n'est garantie par personne.


Questions fréquentes

Question

Quelle est la différence entre une classe et une instance ?

La classe est le plan, l'instance est l'objet construit à partir de ce plan. Le plan ne bouge plus une fois écrit, alors que les instances se créent à volonté pendant l'exécution, chacune avec ses valeurs et sa place en mémoire. Une valeur qui diffère d'un objet à l'autre appartient donc à l'instance.

Question

Combien d'instances peut-on créer à partir d'une seule classe ?

Autant que la mémoire le permet, rien ne les limite par défaut. Une limite, s'il en faut une, se pose à la main : une classmethod sert justement à compter ces créations ou à les encadrer, par exemple pour n'autoriser qu'un seul exemplaire.

Question

Pourquoi l'affichage d'une instance ressemble-t-il à une adresse mémoire ?

Parce que Python, faute d'instructions, se contente du nom de la classe et de l'emplacement de l'objet : il ignore lesquelles de vos valeurs méritent d'être montrées. Définir la méthode magique __repr__ remplace cette ligne par ce que vous jugez utile, le titulaire et le solde par exemple. La formation Python construit ces classes pas à pas.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.