Traduction en français

Bonjour à tous les programmeurs Python en herbe !aujourd'hui, nous allons plonger dans le monde fascinant des décorateurs Python. Imaginez les décorateurs comme des emballages magiques qui peuvent enrichir vos fonctions avec des superpouvoirs. Excitant, non ? Partons ensemble dans ce voyage !

Python - Decorators

Qu'est-ce qu'un Décorateur ?

Imaginez que vous avez un cadeau magnifiquement emballé. Le papier d'emballage ne change pas le cadeau à l'intérieur, mais il le rend plus joli, non ? C'est exactement ce que font les décorateurs à vos fonctions en Python. Ils entourent vos fonctions, ajoutant une fonctionnalité supplémentaire sans modifier la fonction originale elle-même.

Commençons par un exemple simple :

def mon_decorateur(func):
    def wrapper():
        print("Quelque chose se passe avant que la fonction ne soit appelée.")
        func()
        print("Quelque chose se passe après que la fonction ne soit appelée.")
    return wrapper

@mon_decorateur
def dire_bonjour():
    print("Bonjour !")

dire_bonjour()

Si vous exécutez ce code, vous verrez :

Quelque chose se passe avant que la fonction ne soit appelée.
Bonjour !
Quelque chose se passe après que la fonction ne soit appelée.

Analysons cela :

  1. Nous définissons une fonction décoratrice mon_decorateur qui prend une fonction en argument.
  2. À l'intérieur de mon_decorateur, nous définissons une fonction wrapper qui ajoute du comportement avant et après l'appel de la fonction originale.
  3. Nous utilisons la syntaxe @mon_decorateur pour appliquer notre décorateur à la fonction dire_bonjour.
  4. Lorsque nous appelons dire_bonjour(), nous appelons en réalité la version enveloppée de la fonction.

N'est-ce pas pratique ? Nous avons juste ajouté une comportement supplémentaire à notre fonction dire_bonjour sans modifier son code !

Décorateurs avec Arguments

Mais attendez, il y a plus ! Que faire si notre fonction prend des arguments ? Pas de problème ! Nous pouvons modifier notre décorateur pour gérer cela :

def mon_decorateur(func):
    def wrapper(*args, **kwargs):
        print("Avant que la fonction ne soit appelée.")
        result = func(*args, **kwargs)
        print("Après que la fonction ne soit appelée.")
        return result
    return wrapper

@mon_decorateur
def ajouter(a, b):
    return a + b

print(ajouter(3, 5))

Cela donnera :

Avant que la fonction ne soit appelée.
Après que la fonction ne soit appelée.
8

Ici, *args et **kwargs permettent à notre décorateur de travailler avec un nombre quelconque d'arguments positionnels et nommés.

Décorateurs Intégrés

Python est fourni avec certains décorateurs intégrés qui sont extrêmement utiles. Explorons-les !

Le Décorateur @classmethod

Le décorateur @classmethod est utilisé pour définir des méthodes qui opèrent sur la classe elle-même, plutôt que sur des instances de la classe.

class Pizza:
    def __init__(self, ingredients):
        self.ingredients = ingredients

    @classmethod
    def margherita(cls):
        return cls(['mozzarella', 'tomates'])

    @classmethod
    def prosciutto(cls):
        return cls(['mozzarella', 'tomates', 'jambon'])

print(Pizza.margherita().ingredients)
print(Pizza.prosciutto().ingredients)

Cela donnera :

['mozzarella', 'tomates']
['mozzarella', 'tomates', 'jambon']

Ici, margherita et prosciutto sont des méthodes de classe qui créent et renvoient de nouvelles instances de Pizza avec des ingrédients prédéfinis.

Le Décorateur @staticmethod

Les méthodes statiques sont des méthodes qui ne opèrent pas sur l'instance ou la classe. Ce sont juste des fonctions régulières qui se trouvent à l'intérieur d'une classe.

class Math:
    @staticmethod
    def ajouter(a, b):
        return a + b

print(Math.ajouter(5, 10))

Cela donnera :

15

Le Décorateur @property

Le décorateur @property permet de définir des méthodes que vous pouvez accéder comme des attributs.

class Cercle:
    def __init__(self, rayon):
        self._rayon = rayon

    @property
    def rayon(self):
        return self._rayon

    @property
    def surface(self):
        return 3.14 * self._rayon ** 2

c = Cercle(5)
print(c.rayon)
print(c.surface)

Cela donnera :

5
78.5

Ici, nous pouvons accéder à rayon et surface comme s'ils étaient des attributs, mais ce sont en réalité des méthodes.

Le Décorateur @functools.wraps

Ce décorateur est utilisé pour préserver les métadonnées de la fonction originale lors de la création de décorateurs.

from functools import wraps

def mon_decorateur(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """Ceci est la fonction enveloppe"""
        return func(*args, **kwargs)
    return wrapper

@mon_decorateur
def ma_fonction():
    """Ceci est ma fonction"""
    pass

print(ma_fonction.__name__)
print(ma_fonction.__doc__)

Cela donnera :

ma_fonction
Ceci est ma fonction

Sans @wraps, le nom de la fonction et la chaîne de documentation seraient ceux de la fonction enveloppe.

Conclusion

Les décorateurs sont une fonctionnalité puissante en Python qui permet de modifier ou d'enrichir des fonctions et des méthodes. Ils sont largement utilisés dans les frameworks et les bibliothèques pour ajouter des fonctionnalités comme le journalisation, le contrôle d'accès, et plus encore.

N'oubliez pas, la clé pour maîtriser les décorateurs est la pratique. Essayez de créer vos propres décorateurs et de les appliquer à différentes fonctions. Bientôt, vous envelopperez vos fonctions avec des superpouvoirs comme un pro !

Voici un tableau résumant les décorateurs que nous avons couverts :

Décorateur But
@classmethod Définir des méthodes qui opèrent sur la classe elle-même
@staticmethod Définir des méthodes qui ne opèrent pas sur l'instance ou la classe
@property Définir des méthodes qui peuvent être accédées comme des attributs
@functools.wraps Préserver les métadonnées de la fonction originale dans les décorateurs

Bon codage, et que vos fonctions soient toujours magnifiquement décorées !

Credits: Image by storyset