Créez votre première métaclasse

PythonPythonBeginner
Pratiquer maintenant

This tutorial is from open-source community. Access the source code

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire (lab), vous allez apprendre à connaître les métaclasses en Python. En Python, tout, y compris les classes, est un objet. Une métaclasse est une classe qui crée d'autres classes, offrant un moyen puissant de personnaliser la création de classes.

Les objectifs de ce laboratoire sont de comprendre ce qu'est une métaclasse, de créer votre première métaclasse, de l'utiliser pour créer de nouvelles classes et d'observer comment les métaclasses affectent l'héritage de classe. Le fichier mymeta.py sera créé pendant le laboratoire.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/FunctionsGroup -.-> python/build_in_functions("Build-in Functions") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ObjectOrientedProgrammingGroup -.-> python/inheritance("Inheritance") python/ObjectOrientedProgrammingGroup -.-> python/class_static_methods("Class Methods and Static Methods") subgraph Lab Skills python/function_definition -.-> lab-132519{{"Créez votre première métaclasse"}} python/build_in_functions -.-> lab-132519{{"Créez votre première métaclasse"}} python/classes_objects -.-> lab-132519{{"Créez votre première métaclasse"}} python/inheritance -.-> lab-132519{{"Créez votre première métaclasse"}} python/class_static_methods -.-> lab-132519{{"Créez votre première métaclasse"}} end

Comprendre les métaclasses

Les métaclasses sont une fonctionnalité avancée mais puissante en Python. En tant que débutant, vous vous demandez peut - être ce que sont les métaclasses et pourquoi elles sont importantes. Avant de commencer à créer notre première métaclasse, prenons un moment pour comprendre ces concepts.

Qu'est - ce qu'une métaclasse ?

En Python, tout est un objet, y compris les classes. Tout comme une classe normale est utilisée pour créer des instances, une métaclasse est utilisée pour créer des classes. Par défaut, Python utilise la métaclasse intégrée type pour créer toutes les classes.

Découpons le processus de création de classe étape par étape :

  1. Tout d'abord, Python lit la définition de classe que vous avez écrite dans votre code. C'est là que vous définissez le nom de la classe, ses attributs et ses méthodes.
  2. Ensuite, Python collecte des informations importantes sur la classe, telles que le nom de la classe, les classes de base dont elle hérite et tous ses attributs.
  3. Après cela, Python transmet ces informations collectées à la métaclasse. La métaclasse est chargée de prendre ces informations et de créer l'objet de classe réel.
  4. Enfin, la métaclasse crée et retourne la nouvelle classe.

Une métaclasse vous donne le pouvoir de personnaliser ce processus de création de classe. Vous pouvez modifier ou inspecter les classes pendant leur création, ce qui peut être très utile dans certains scénarios.

Visualisons cette relation pour faciliter la compréhension :

Metaclass → creates → Class → creates → Instance

Dans ce laboratoire (lab), nous allons créer notre propre métaclasse. En faisant cela, vous pourrez voir ce processus de création de classe en action et mieux comprendre le fonctionnement des métaclasses.

✨ Vérifier la solution et pratiquer

Créer votre première métaclasse

Maintenant, nous allons créer notre toute première métaclasse. Avant de commencer à coder, comprenons ce qu'est une métaclasse. En Python, une métaclasse est une classe qui crée d'autres classes. C'est comme un modèle pour les classes. Lorsque vous définissez une classe en Python, Python utilise une métaclasse pour créer cette classe. Par défaut, Python utilise la métaclasse type. Dans cette étape, nous allons définir une métaclasse personnalisée qui affiche des informations sur la classe qu'elle crée. Cela nous aidera à comprendre le fonctionnement interne des métaclasses.

  1. Ouvrez VSCode dans le WebIDE et créez un nouveau fichier appelé mymeta.py dans le répertoire /home/labex/project. C'est là que nous allons écrire notre code pour la métaclasse.

  2. Ajoutez le code suivant au fichier :

## mymeta.py

class mytype(type):
    @staticmethod
    def __new__(meta, name, bases, __dict__):
        print("Creating class :", name)
        print("Base classes   :", bases)
        print("Attributes     :", list(__dict__))
        return super().__new__(meta, name, bases, __dict__)

class myobject(metaclass=mytype):
    pass

Analysons ce que ce code fait :

  • Tout d'abord, nous définissons une nouvelle classe nommée mytype qui hérite de type. Étant donné que type est la métaclasse par défaut en Python, en héritant d'elle, nous créons notre propre métaclasse personnalisée.
  • Ensuite, nous redéfinissons la méthode __new__. En Python, la méthode __new__ est une méthode spéciale qui est appelée lors de la création d'un nouvel objet. Dans le contexte d'une métaclasse, elle est appelée lors de la création d'une nouvelle classe.
  • À l'intérieur de notre méthode __new__, nous affichons quelques informations sur la classe en cours de création. Nous affichons le nom de la classe, ses classes de base et ses attributs. Après cela, nous appelons la méthode __new__ du parent en utilisant super().__new__(meta, name, bases, __dict__). Cela est important car c'est cela qui crée effectivement la classe.
  • Enfin, nous créons une classe de base nommée myobject et spécifions qu'elle doit utiliser notre métaclasse personnalisée mytype.

La méthode __new__ prend les paramètres suivants :

  • meta : Cela fait référence à la métaclasse elle - même. Dans notre cas, c'est mytype.
  • name : C'est le nom de la classe en cours de création.
  • bases : C'est un tuple contenant les classes de base dont la nouvelle classe hérite.
  • __dict__ : C'est un dictionnaire qui contient les attributs de la classe.
  1. Enregistrez le fichier en appuyant sur Ctrl+S ou en cliquant sur Fichier > Enregistrer. Enregistrer le fichier garantit que votre code est conservé et peut être exécuté plus tard.
✨ Vérifier la solution et pratiquer

Utiliser votre métaclasse

Maintenant, nous allons créer une classe qui utilise notre métaclasse par héritage. Cela nous aidera à comprendre comment la métaclasse est appelée lorsque la classe est définie.

Une métaclasse en Python est une classe qui crée d'autres classes. Lorsque vous définissez une classe, Python utilise une métaclasse pour construire l'objet de cette classe. En utilisant l'héritage, nous pouvons spécifier quelle métaclasse une classe doit utiliser.

  1. Ouvrez le fichier mymeta.py et ajoutez le code suivant à la fin du fichier :
class Stock(myobject):
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price

    def cost(self):
        return self.shares * self.price

    def sell(self, nshares):
        self.shares -= nshares

Ici, nous définissons une classe Stock qui hérite de myobject. La méthode __init__ est une méthode spéciale dans les classes Python. Elle est appelée lorsque un objet de la classe est créé et est utilisée pour initialiser les attributs de l'objet. La méthode cost calcule le coût total des actions, et la méthode sell réduit le nombre d'actions.

  1. Enregistrez le fichier en appuyant sur Ctrl+S. Enregistrer le fichier garantit que les modifications que vous avez apportées sont enregistrées et peuvent être exécutées plus tard.

  2. Maintenant, exécutons le fichier pour voir ce qui se passe. Ouvrez un terminal dans le WebIDE et exécutez :

cd /home/labex/project
python3 mymeta.py

La commande cd change le répertoire de travail actuel en /home/labex/project, et python3 mymeta.py exécute le script Python mymeta.py.

Vous devriez voir une sortie similaire à ceci :

Creating class : myobject
Base classes   : ()
Attributes     : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes   : (<class '__main__.myobject'>,)
Attributes     : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']

Cette sortie montre que notre métaclasse est invoquée lorsque les classes myobject et Stock sont créées. Remarquez comment :

  • Pour Stock, les classes de base incluent myobject car Stock hérite de myobject.
  • La liste des attributs inclut toutes les méthodes que nous avons définies (__init__, cost, sell) ainsi que certains attributs par défaut.
  1. Interagissons avec notre classe Stock. Créez un nouveau fichier nommé test_stock.py avec le contenu suivant :
## test_stock.py
from mymeta import Stock

## Create a new Stock instance
apple = Stock("AAPL", 100, 154.50)

## Use the methods
print(f"Stock: {apple.name}, Shares: {apple.shares}, Price: ${apple.price}")
print(f"Total cost: ${apple.cost()}")

## Sell some shares
apple.sell(10)
print(f"After selling 10 shares: {apple.shares} shares remaining")
print(f"Updated cost: ${apple.cost()}")

Dans ce code, nous importons la classe Stock du module mymeta. Ensuite, nous créons une instance de la classe Stock nommée apple. Nous utilisons les méthodes de la classe Stock pour afficher des informations sur les actions, calculer le coût total, vendre quelques actions, puis afficher les informations mises à jour.

  1. Exécutez ce fichier pour tester notre classe Stock :
python3 test_stock.py

Vous devriez voir une sortie comme celle - ci :

Creating class : myobject
Base classes   : ()
Attributes     : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes   : (<class 'mymeta.myobject'>,)
Attributes     : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']
Stock: AAPL, Shares: 100, Price: $154.5
Total cost: $15450.0
After selling 10 shares: 90 shares remaining
Updated cost: $13905.0

Remarquez que les informations de notre métaclasse sont affichées en premier, suivies de la sortie de notre script de test. Cela s'explique par le fait que la métaclasse est invoquée lorsque la classe est définie, ce qui se produit avant l'exécution du code dans le script de test.

✨ Vérifier la solution et pratiquer

Explorer l'héritage des métaclasses

Les métaclasses ont une caractéristique fascinante : elles sont « collantes ». Cela signifie qu'une fois qu'une classe utilise une métaclasse, toutes ses sous - classes dans la hiérarchie d'héritage utiliseront également la même métaclasse. En d'autres termes, la propriété de la métaclasse se propage à travers la chaîne d'héritage.

Voyons cela en action :

  1. Tout d'abord, ouvrez le fichier mymeta.py. À la fin de ce fichier, nous allons ajouter une nouvelle classe. Cette classe, nommée MyStock, héritera de la classe Stock. La méthode __init__ est utilisée pour initialiser les attributs de l'objet, et nous appelons la méthode __init__ de la classe parente en utilisant super().__init__ pour initialiser les attributs communs. La méthode info est utilisée pour retourner une chaîne formatée avec des informations sur les actions. Ajoutez le code suivant :
class MyStock(Stock):
    def __init__(self, name, shares, price, category):
        super().__init__(name, shares, price)
        self.category = category

    def info(self):
        return f"{self.name} ({self.category}): {self.shares} shares at ${self.price}"
  1. Après avoir ajouté le code, enregistrez le fichier mymeta.py. Enregistrer le fichier garantit que les modifications que nous avons apportées sont enregistrées et peuvent être utilisées plus tard.

  2. Maintenant, nous allons créer un nouveau fichier nommé test_inheritance.py pour tester le comportement d'héritage de la métaclasse. Dans ce fichier, nous allons importer la classe MyStock depuis le fichier mymeta.py. Ensuite, nous allons créer une instance de la classe MyStock, appeler ses méthodes et afficher les résultats pour voir comment la métaclasse fonctionne via l'héritage. Ajoutez le code suivant à test_inheritance.py :

## test_inheritance.py
from mymeta import MyStock

## Create a MyStock instance
tech_stock = MyStock("MSFT", 50, 305.75, "Technology")

## Test the methods
print(tech_stock.info())
print(f"Total cost: ${tech_stock.cost()}")

## Sell some shares
tech_stock.sell(5)
print(f"After selling: {tech_stock.shares} shares remaining")
print(f"Updated cost: ${tech_stock.cost()}")
  1. Enfin, exécutez le fichier test_inheritance.py pour voir la métaclasse en action via l'héritage. Ouvrez votre terminal, accédez au répertoire où se trouve le fichier test_inheritance.py et exécutez la commande suivante :
python3 test_inheritance.py

Vous devriez voir une sortie similaire à :

Creating class : myobject
Base classes   : ()
Attributes     : ['__module__', '__qualname__', '__doc__']
Creating class : Stock
Base classes   : (<class 'mymeta.myobject'>,)
Attributes     : ['__module__', '__qualname__', '__init__', 'cost', 'sell', '__doc__']
Creating class : MyStock
Base classes   : (<class 'mymeta.Stock'>,)
Attributes     : ['__module__', '__qualname__', '__init__', 'info', '__doc__']
MSFT (Technology): 50 shares at $305.75
Total cost: $15287.5
After selling: 45 shares remaining
Updated cost: $13758.75

Remarquez que même si nous n'avons pas spécifié explicitement une métaclasse pour la classe MyStock, la métaclasse est toujours appliquée. Cela démontre clairement comment les métaclasses se propagent via l'héritage.

Utilisations pratiques des métaclasses

Dans notre exemple, la métaclasse ne fait que afficher des informations sur les classes. Cependant, les métaclasses ont de nombreuses applications pratiques dans la programmation réelle :

  1. Validation : Vous pouvez utiliser des métaclasses pour vérifier si une classe a les méthodes ou les attributs requis. Cela permet de s'assurer que les classes répondent à certains critères avant d'être utilisées.
  2. Enregistrement : Les métaclasses peuvent enregistrer automatiquement les classes dans un registre. Cela est utile lorsque vous avez besoin de suivre toutes les classes d'un certain type.
  3. Respect des interfaces : Elles peuvent être utilisées pour s'assurer que les classes implémentent les interfaces requises. Cela contribue à maintenir une structure cohérente dans votre code.
  4. Programmation orientée aspect : Les métaclasses peuvent ajouter des comportements aux méthodes. Par exemple, vous pouvez ajouter une journalisation ou une surveillance des performances aux méthodes sans modifier directement le code de la méthode.
  5. Systèmes ORM : Dans les systèmes de mappage objet - relationnel (ORM) comme Django ou SQLAlchemy, les métaclasses sont utilisées pour mapper les classes aux tables de base de données. Cela simplifie les opérations de base de données dans votre application.

Les métaclasses sont très puissantes, mais elles doivent être utilisées avec modération. Comme l'a dit un jour Tim Peters (connnu pour le Zen de Python) : « Les métaclasses sont une magie plus profonde que 99 % des utilisateurs n'auront jamais à se soucier. »

✨ Vérifier la solution et pratiquer

Résumé

Dans ce laboratoire (lab), vous avez appris ce que sont les métaclasses et comment elles fonctionnent en Python. Vous avez créé avec succès votre première métaclasse personnalisée pour surveiller la création de classes et l'avez utilisée pour générer de nouvelles classes. De plus, vous avez observé comment les métaclasses se propagent à travers les hiérarchies d'héritage.

Les métaclasses sont une fonctionnalité avancée de Python qui offre un contrôle sur la création de classes. Bien que vous n'ayez peut - être pas besoin de créer des métaclasses tous les jours, comprendre ce concept vous permet de mieux saisir le système d'objets de Python et ouvre des possibilités puissantes pour le développement de frameworks et de bibliothèques. Pour en savoir plus, explorez la documentation officielle de Python et les livres avancés sur la métaprogrammation en Python.