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 par ce 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 le 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 permier 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 é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.