2.21. Méthodes et attributs

Une méthode est une fonction définie à l’intérieur d’une classe. Le premier paramètre est l’instance sur laquelle la méthode est appelée ; la convention est de le nommer self.

2.21.1. Méthodes d’instance

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def magnitude(self):
        return (self.x ** 2 + self.y ** 2) ** 0.5

p = Point(3, 4)
print(p.magnitude())

Sortie

5.0

L’appel p.magnitude() passe p comme self automatiquement. Les corps de méthode lisent et mettent à jour les attributs via self de la même façon que les fonctions lisent et mettent à jour des noms via les paramètres.

2.21.2. Attributs d’instance et attributs de classe

Les attributs affectés à self – généralement à l’intérieur de __init__ – appartiennent à cette seule instance :

a = Point(1, 2)
b = Point(10, 20)
a.x = 99
print(a.x, b.x)           # 99 10

a.x et b.x sont des emplacements de stockage différents ; modifier l’un n’affecte pas l’autre.

Les noms affectés dans le corps de la classe, en dehors de toute méthode, sont partagés par toutes les instances de la classe :

class Counter:
    kind = "tally"        # class attribute -- shared

    def __init__(self):
        self.value = 0    # instance attribute -- per instance

a = Counter()
b = Counter()
print(a.kind, b.kind)     # tally tally
Un bloc de classe en haut contenant des méthodes partagées et l'attribut de classe « kind » ; en dessous, deux boîtes d'instance contenant chacune leur propre attribut « value », avec des flèches de chaque instance vers la classe.

Les attributs de classe résident sur la classe elle-même et sont partagés. Les attributs d’instance résident sur chaque instance.

Un attribut de classe s’atteint de la même façon qu’un attribut d’instance (a.kind) ; Python regarde d’abord sur l’instance, puis sur la classe. Affecter une valeur à a.kind créerait un nouvel attribut d”instance qui masque celui de la classe, laissant b.kind inchangé.

Utilisez les attributs de classe pour les constantes et les valeurs par défaut que chaque instance doit voir de la même façon. Utilisez les attributs d’instance pour l’état dont chaque objet doit posséder sa propre copie.

2.21.3. __str__ et __repr__

Deux méthodes spéciales contrôlent la façon dont une instance s’affiche. __str__ renvoie la chaîne « conviviale » utilisée par print() ; __repr__ renvoie la chaîne « développeur » utilisée au REPL et dans les affichages de conteneurs :

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return "(" + str(self.x) + ", " + str(self.y) + ")"

    def __repr__(self):
        return "Point(" + str(self.x) + ", " + str(self.y) + ")"

p = Point(3, 4)
print(p)            # uses __str__
print([p, p])       # uses __repr__ inside the list

Sortie

(3, 4)
[Point(3, 4), Point(3, 4)]

Si seule __repr__ est définie, print() s’y rabat – donc une unique __repr__ bien écrite suffit généralement. Ne définissez __str__ en plus que lorsque la forme conviviale doit avoir une apparence différente de la forme développeur. Visez une __repr__ qui ressemble à l’appel qui recréerait l’objet ; le débogage devient considérablement plus facile lorsque les valeurs affichées sont sans ambiguïté.