Outils pour les classes en Python

Ce billet date de plusieurs années, ses informations peuvent être devenues obsolètes.

Raymond Hettinger présentait en 2013 (vidéo slides) les outils intégrés de Python permettant de créer des classes.

Du temps est passé depuis, mais ça reste un classique.

Voici mes notes.

1) Hériter d'object (en Python 2)

L'ajout de classes au langage Python a été essentiellement une réflexion après coup.

Les New-Style Classes sont arrivées en Python 2 et nécessitent d'hériter d'object pour corriger les bogues des Classic-Style Classes.

En Python 3 il n'y a plus que des New-Style Classes, plus besoin d'hériter explicitement de object.

Vous pouvez lire la prose de Guido van Rossum dans The Inside Story on New-Style Classes et New-style Classes pour avoir tous les détails.

2) __init__ n'est pas un constructeur

La méthode dunder init définit comment les nouvelles instances sont initialisées après leur création.

Son rôle est de peupler les variables d'instance.

3) self comme premier argument explicite

Les méthodes normales des classes ont self comme premier argument explicite.

L'appellation self est une convention culturelle en Python.

Le caractère explicite de self est expliqué dans la documentation et défendu dans Why explicit self has to stay.

4) Variables d'instance vs variables de classe

Les variables d'instance référencent des données uniques à une instance.

Les variables de classe référencent des données partagées par toutes les instances.

5) Exposer des attributs est courant et normal

Les variables de classe sont déclarées directement dans le corps de la classe.

Elles sont ensuite accessibles comme des attributs depuis la classe elle-même.

Exemple en Django :

class Aircraft(models.Model):

    ENGINE_TURBOPROP = '1'
    ENGINE_JET = '2'
    ENGINE_PISTON = '3'
    ENGINE_CHOICES = (
        (ENGINE_TURBOPROP, "Turboprop"),
        (ENGINE_JET, "Jet"),
        (ENGINE_PISTON, "Piston"),
    )

    # ...

dict(Aircraft.ENGINE_CHOICES)
{'1': 'Turboprop', '2': 'Jet', '3': 'Piston'}

6) Pas de variables privées, rôle de __

Il n'existe pas de variables privées en Python.

C'est culturel. Ça choque parfois les gens qui ont appris l'objet avec Java ou C++, mais :

Truth is, you don't really need them.

Il existe tout de même un cas d'usage légitime pour les variable privées : éviter des conflits de noms avec des sous-classes. Python utilise le name mangling pour ça, détecté en préfixant les variables concernées avec un dunder (__).

7) @classmethod pour créer des constructeurs alternatifs

You should have more than one constructor!

import math

class Circle:

    def __init__(self, radius):
        self.radius = radius

    @classmethod
    def from_bbd(cls, bbd):
        radius = bbd / 2.0 / math.sqrt(2.0)
        return cls(radius)

c = Circle.from_bbd(25.1)
c.radius
8.874190103891172

Il est important de passer cls comme premier argument explicite pour supporter l'héritage !

Quelques exemples : dict.fromkeys(), int.from_bytes(), datetime.utcnow(), datetime.fromtimestamp(), datetime.now() etc.

8) @staticmethod attache des fonctions à des classes

Si vous devez créer une instance juste pour appeler une fonction, c'est que vous avez besoin de @staticmethod !

@staticmethod attache des fonctions à des classes.

Pas de self en premier argument ! La méthode statique peut être invoquée soit depuis la classe, soit depuis une instance.

On s'en sert surtout pour améliorer la repérabilité et pour s'assurer que la méthode soit utilisée dans un contexte approprié.

9) @property invoque une méthode lors de l'accès à un attribut

En décorant une méthode avec @property, on peut y accéder comme un simple attribut, sans les ().

Ça permet de s'affranchir de l'écriture verbeuse de getters et de setters.

Ça donne aussi la possibilité de pouvoir appliquer des traitements sur un attribut de classe a posteriori sans que les utilisateurs de la classe n'aient besoin de modifier leur code.


Who learned something new? :)

Avant Voir le contenu des volumes nommés de Docker for Mac Après Acrimonie vidéoludique

Tag Kemar Joint