Attributs et instances de classe

Rappels

Voici un exemple de classe qui contient une méthode :

class MaClasse
    def ma_méthode(self):
        print(self.mon_attribut)

Le bloc indenté en-dessous du mot-clé class s’appelle le corps de la classe. Et les méthodes sont définies avec le mot-clé def dans le corps de la classe.

On dit que ce sont des méthodes d’instance parce qu’il faut créer une instance pour pouvoir les appeler :

mon_instance = MaClasse()
mon_instance.ma_méthode()

Attributs de classes

On peut également déclarer des variables dans le corps d’une classe.

On crée ainsi des attributs de classe :

class MaClasse:
    mon_attribut_de_classe = 42

Ici mon_attribut_de_classe existe à la fois dans les instances de MaClasse et dans la classe elle-même :

print(MaClasse.mon_attribut_de_classe)
# affiche: 42
mon_instance = MaClasse()
print(mon_instance.mon_attribut_de_classe)
# affiche: 42

Un point important est que les attributs de classe sont partagés entre toutes les instances. Voici un exemple d’utilisation possible :

class Voiture:
    nombre_total_de_voitures_fabriquées = 0

    def __init__(self, marque, couleur):
        print("Construction d'une", marque, couleur)
        Voiture.nombre_total_de_voitures_fabriquées += 1


ferrari_1 = Voiture("Ferrari", "rouge")
mercedes_1  = Voiture("Mercedes, "noire")
ferrari_2 = Voiture("Ferrari", "rouge")
print("total:", Voiture.nombre_total_de_voitures_fabriquées)
# affiche:
# Construction d'une Ferrari rouge
# Construction d'une Mercedes noire
# Construction d'une Ferrari rouge
# total: 3

Notez que pour changer l’attribut de classe depuis une méthode, (comme dans la méthode __init__ ci-dessus) on utilise le nom de la classe directement, et non pas self.

Méthodes de classes

On peut aussi définir des méthodes de classes avec le décorateur classmethod.

Dans ce cas, le premier argument s’appelle cls et prend la valeur de la classe elle-même. Pour poursuivre sur notre exemple :

class Voiture:
    nombre_total_de_voitures_fabriquées = 0

    def __init__(self, marque, couleur):
        print("Construction d'une", marque, couleur)
        Voiture.nombre_total_de_voitures_fabriquées += 1

    @classmethod
    def fabrique_ferrari(cls):
        return cls("ferrari", "rouge")


ferrari = Voiture.fabrique_ferrari()

Détaillons ce qu’il se passe sur la dernière ligne : à gauche du signe égal, il y a une variable, et à droite une expression (Voiture.fabrique_ferrari())

L’expression est constitué d’une classe à gauche du point (Voiture), et d’un attribut à droite du point fabrique_ferrari, suivi de parenthèses.

Comme fabrique_ferrari est une méthode de classe, on va appeler la méthode de classe fabrique_ferrari en lui passant la classe courante en argument.

On arrive ainsi dans le corps de la méthode de classe fabrique_ferrari, et cls vaut la classe Voiture.

Finalement, on évalue l’expression cls("ferrari", rouge") en remplaçant cls par sa valeur, ce qui donne Voiture("ferrari", "rouge") qui correspond bien à ce qu’on obtient : Une instance de la classe Voiture.