Apprenez les décorateurs de classe

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 les décorateurs de classe en Python et revoir et étendre les descripteurs Python. En combinant ces concepts, vous pourrez créer des structures de code puissantes et propres.

Dans ce laboratoire (lab), vous allez vous appuyer sur les concepts de descripteurs précédents et les étendre à l'aide de décorateurs de classe. Cette combinaison vous permet de créer un code plus propre et plus facilement maintenable avec des capacités de validation améliorées. Les fichiers à modifier sont validate.py et structure.py.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/BasicConceptsGroup(["Basic Concepts"]) python(("Python")) -.-> python/ControlFlowGroup(["Control Flow"]) python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ObjectOrientedProgrammingGroup(["Object-Oriented Programming"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/BasicConceptsGroup -.-> python/type_conversion("Type Conversion") python/ControlFlowGroup -.-> python/conditional_statements("Conditional Statements") python/FunctionsGroup -.-> python/function_definition("Function Definition") python/ObjectOrientedProgrammingGroup -.-> python/classes_objects("Classes and Objects") python/ObjectOrientedProgrammingGroup -.-> python/inheritance("Inheritance") python/ObjectOrientedProgrammingGroup -.-> python/encapsulation("Encapsulation") python/ObjectOrientedProgrammingGroup -.-> python/class_static_methods("Class Methods and Static Methods") python/AdvancedTopicsGroup -.-> python/decorators("Decorators") subgraph Lab Skills python/type_conversion -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/conditional_statements -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/function_definition -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/classes_objects -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/inheritance -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/encapsulation -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/class_static_methods -.-> lab-132516{{"Apprenez les décorateurs de classe"}} python/decorators -.-> lab-132516{{"Apprenez les décorateurs de classe"}} end

Mise en œuvre de la vérification de type avec des descripteurs

Dans cette étape, nous allons créer une classe Stock qui utilise des descripteurs pour la vérification de type. Mais d'abord, comprenons ce que sont les descripteurs. Les descripteurs sont une fonctionnalité très puissante en Python. Ils vous donnent le contrôle sur la façon dont les attributs sont accédés dans les classes.

Les descripteurs sont des objets qui définissent comment les attributs sont accédés sur d'autres objets. Ils le font en implémentant des méthodes spéciales telles que __get__, __set__ et __delete__. Ces méthodes permettent aux descripteurs de gérer la façon dont les attributs sont récupérés, définis et supprimés. Les descripteurs sont très utiles pour implémenter la validation, la vérification de type et les propriétés calculées. Par exemple, vous pouvez utiliser un descripteur pour vous assurer qu'un attribut est toujours un nombre positif ou une chaîne de caractères d'un certain format.

Le fichier validate.py contient déjà des classes de validateurs (String, PositiveInteger, PositiveFloat). Nous pouvons utiliser ces classes pour valider les attributs de notre classe Stock.

Maintenant, créons notre classe Stock avec des descripteurs.

  1. Tout d'abord, ouvrez le fichier stock.py dans l'éditeur. Vous pouvez le faire en exécutant la commande suivante dans votre terminal :
code ~/project/stock.py

Cette commande utilise l'éditeur code pour ouvrir le fichier stock.py situé dans le répertoire ~/project.

  1. Une fois le fichier ouvert, remplacez le contenu de remplacement par le code suivant :
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    _fields = ('name', 'shares', 'price')
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

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

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

## Create an __init__ method based on _fields
Stock.create_init()

Analysons ce que ce code fait. Le tuple _fields définit les attributs de la classe Stock. Ce sont les noms des attributs que nos objets Stock auront.

Les attributs name, shares et price sont définis comme des objets descripteurs. Le descripteur String() garantit que l'attribut name est une chaîne de caractères. Le descripteur PositiveInteger() s'assure que l'attribut shares est un entier positif. Et le descripteur PositiveFloat() garantit que l'attribut price est un nombre à virgule flottante positif.

La propriété cost est une propriété calculée. Elle calcule le coût total du stock en fonction du nombre d'actions et du prix par action.

La méthode sell est utilisée pour réduire le nombre d'actions. Lorsque vous appelez cette méthode avec un nombre d'actions à vendre, elle soustrait ce nombre de l'attribut shares.

La ligne Stock.create_init() crée dynamiquement une méthode __init__ pour notre classe. Cette méthode nous permet de créer des objets Stock en passant les valeurs pour les attributs name, shares et price.

  1. Après avoir ajouté le code, enregistrez le fichier. Cela garantira que vos modifications sont enregistrées et peuvent être utilisées lorsque vous exécutez les tests.

  2. Maintenant, exécutons les tests pour vérifier votre implémentation. Tout d'abord, changez de répertoire pour le répertoire ~/project en exécutant la commande suivante :

cd ~/project

Ensuite, exécutez les tests en utilisant la commande suivante :

python3 teststock.py

Si votre implémentation est correcte, vous devriez voir une sortie similaire à ceci :

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Cette sortie signifie que tous les tests passent. Les descripteurs valident avec succès les types de chaque attribut !

Essayons de créer un objet Stock dans l'interpréteur Python. Tout d'abord, assurez-vous d'être dans le répertoire ~/project. Ensuite, exécutez la commande suivante :

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Vous devriez voir la sortie suivante :

Stock('GOOG', 100, 490.1)
Cost: 49010.0

Vous avez réussi à implémenter des descripteurs pour la vérification de type ! Maintenant, améliorons ce code encore plus.

✨ Vérifier la solution et pratiquer

Création d'un décorateur de classe pour la validation

Dans l'étape précédente, notre implémentation fonctionnait, mais il y avait une redondance. Nous devions spécifier à la fois le tuple _fields et les attributs descripteurs. Ce n'est pas très efficace, et nous pouvons l'améliorer. En Python, les décorateurs de classe sont un outil puissant qui peut nous aider à simplifier ce processus. Un décorateur de classe est une fonction qui prend une classe en argument, la modifie d'une certaine manière, puis retourne la classe modifiée. En utilisant un décorateur de classe, nous pouvons extraire automatiquement les informations de champ à partir des descripteurs, ce qui rendra notre code plus propre et plus facilement maintenable.

Créons un décorateur de classe pour simplifier notre code. Voici les étapes à suivre :

  1. Tout d'abord, ouvrez le fichier structure.py. Vous pouvez utiliser la commande suivante dans le terminal :
code ~/project/structure.py

Cette commande ouvrira le fichier structure.py dans votre éditeur de code.

  1. Ensuite, ajoutez le code suivant en haut du fichier structure.py, juste après les instructions d'importation. Ce code définit notre décorateur de classe :
from validate import Validator

def validate_attributes(cls):
    """
    Class decorator that extracts Validator instances
    and builds the _fields list automatically
    """
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Create initialization method
    cls.create_init()

    return cls

Analysons ce que fait ce décorateur :

  • Il crée d'abord une liste vide appelée validators. Ensuite, il itère sur tous les attributs de la classe en utilisant vars(cls).items(). Si un attribut est une instance de la classe Validator, il ajoute cet attribut à la liste validators.
  • Après cela, il définit l'attribut _fields de la classe. Il crée une liste de noms à partir des validateurs de la liste validators et l'assigne à cls._fields.
  • Enfin, il appelle la méthode create_init() de la classe pour générer la méthode __init__, puis retourne la classe modifiée.
  1. Une fois que vous avez ajouté le code, enregistrez le fichier structure.py. Enregistrer le fichier garantit que vos modifications sont conservées.

  2. Maintenant, nous devons modifier notre fichier stock.py pour utiliser ce nouveau décorateur. Ouvrez le fichier stock.py en utilisant la commande suivante :

code ~/project/stock.py
  1. Mettez à jour le fichier stock.py pour utiliser le décorateur validate_attributes. Remplacez le code existant par le suivant :
## stock.py

from structure import Structure, validate_attributes
from validate import String, PositiveInteger, PositiveFloat

@validate_attributes
class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

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

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

Remarquez les modifications que nous avons apportées :

  • Nous avons ajouté le décorateur @validate_attributes juste au-dessus de la définition de la classe Stock. Cela indique à Python d'appliquer le décorateur validate_attributes à la classe Stock.
  • Nous avons supprimé la déclaration explicite de _fields car le décorateur s'en occupera automatiquement.
  • Nous avons également supprimé l'appel à Stock.create_init() car le décorateur s'occupe de créer la méthode __init__.

En conséquence, la classe est maintenant plus simple et plus propre. Le décorateur s'occupe de tous les détails que nous devions gérer manuellement.

  1. Après avoir apporté ces modifications, nous devons vérifier que tout fonctionne toujours comme prévu. Exécutez les tests à nouveau en utilisant les commandes suivantes :
cd ~/project
python3 teststock.py

Si tout fonctionne correctement, vous devriez voir la sortie suivante :

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Cette sortie indique que tous les tests ont réussi.

Testons également notre classe Stock de manière interactive. Exécutez la commande suivante dans le terminal :

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Vous devriez voir la sortie suivante :

Stock('GOOG', 100, 490.1)
Cost: 49010.0

Super ! Vous avez réussi à implémenter un décorateur de classe qui simplifie notre code en gérant automatiquement les déclarations de champ et l'initialisation. Cela rend notre code plus efficace et plus facile à maintenir.

✨ Vérifier la solution et pratiquer

Application de décorateurs via l'héritage

Dans l'Étape 2, nous avons créé un décorateur de classe qui simplifie notre code. Un décorateur de classe est un type spécial de fonction qui prend une classe en argument et retourne une classe modifiée. C'est un outil utile en Python pour ajouter des fonctionnalités aux classes sans modifier leur code d'origine. Cependant, nous devons toujours appliquer explicitement le décorateur @validate_attributes à chaque classe. Cela signifie que chaque fois que nous créons une nouvelle classe qui nécessite une validation, nous devons nous souvenir d'ajouter ce décorateur, ce qui peut être un peu fastidieux.

Nous pouvons améliorer cela en appliquant le décorateur automatiquement par héritage. L'héritage est un concept fondamental en programmation orientée objet où une sous - classe peut hériter d'attributs et de méthodes d'une classe mère. La méthode __init_subclass__ de Python a été introduite en Python 3.6 pour permettre aux classes mères de personnaliser l'initialisation des sous - classes. Cela signifie que lorsqu'une sous - classe est créée, la classe mère peut effectuer certaines actions sur elle. Nous pouvons utiliser cette fonctionnalité pour appliquer automatiquement notre décorateur à toute classe qui hérite de Structure.

Implémentons cela :

  1. Ouvrez le fichier structure.py :
code ~/project/structure.py

Ici, nous utilisons la commande code pour ouvrir le fichier structure.py dans un éditeur de code. Ce fichier contient la définition de la classe Structure, et nous allons la modifier pour utiliser la méthode __init_subclass__.

  1. Ajoutez la méthode __init_subclass__ à la classe Structure :
class Structure:
    _fields = ()
    _types = ()

    def __init__(self, *args):
        if len(args) != len(self._fields):
            raise TypeError(f'Expected {len(self._fields)} arguments')
        for name, val in zip(self._fields, args):
            setattr(self, name, val)

    def __repr__(self):
        values = ', '.join(repr(getattr(self, name)) for name in self._fields)
        return f'{type(self).__name__}({values})'

    @classmethod
    def create_init(cls):
        '''
        Create an __init__ method from _fields
        '''
        body = 'def __init__(self, %s):\n' % ', '.join(cls._fields)
        for name in cls._fields:
            body += f'    self.{name} = {name}\n'

        ## Execute the function creation code
        namespace = {}
        exec(body, namespace)
        setattr(cls, '__init__', namespace['__init__'])

    @classmethod
    def __init_subclass__(cls):
        validate_attributes(cls)

La méthode __init_subclass__ est une méthode de classe, ce qui signifie qu'elle peut être appelée sur la classe elle - même plutôt que sur une instance de la classe. Lorsqu'une sous - classe de Structure est créée, cette méthode sera automatiquement appelée. À l'intérieur de cette méthode, nous appelons le décorateur validate_attributes sur la sous - classe cls. De cette façon, chaque sous - classe de Structure aura automatiquement le comportement de validation.

  1. Enregistrez le fichier.

Après avoir apporté des modifications au fichier structure.py, nous devons l'enregistrer pour que les modifications soient appliquées.

  1. Maintenant, mettons à jour notre fichier stock.py pour tirer parti de cette nouvelle fonctionnalité :
code ~/project/stock.py

Nous ouvrons le fichier stock.py pour le modifier. Ce fichier contient la définition de la classe Stock, et nous allons la faire hériter de la classe Structure pour utiliser l'application automatique du décorateur.

  1. Modifiez le fichier stock.py pour supprimer le décorateur explicite :
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

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

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

Notez que nous :

  • Avons supprimé l'import de validate_attributes car nous n'avons plus besoin de l'importer explicitement puisque le décorateur est appliqué automatiquement par héritage.
  • Avons supprimé le décorateur @validate_attributes car la méthode __init_subclass__ de la classe Structure s'en occupera.
  • Le code dépend maintenant uniquement de l'héritage de Structure pour obtenir le comportement de validation.
  1. Exécutez les tests à nouveau pour vérifier que tout fonctionne toujours :
cd ~/project
python3 teststock.py

Exécuter les tests est important pour nous assurer que nos modifications n'ont rien cassé. Si tous les tests passent, cela signifie que l'application automatique du décorateur par héritage fonctionne correctement.

Vous devriez voir tous les tests passer :

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK

Testons à nouveau notre classe Stock pour nous assurer qu'elle fonctionne comme prévu :

cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); print(s); print(f'Cost: {s.cost}')"

Cette commande crée une instance de la classe Stock et affiche sa représentation et le coût. Si la sortie est conforme aux attentes, cela signifie que la classe Stock fonctionne correctement avec l'application automatique du décorateur.

Sortie :

Stock('GOOG', 100, 490.1)
Cost: 49010.0

Cette implémentation est encore plus propre ! En utilisant __init_subclass__, nous avons éliminé le besoin d'appliquer explicitement des décorateurs. Toute classe qui hérite de Structure obtient automatiquement le comportement de validation.

✨ Vérifier la solution et pratiquer

Ajout de la fonctionnalité de conversion de lignes

En programmation, il est souvent utile de créer des instances d'une classe à partir de lignes de données, notamment lorsqu'on manipule des données issues de sources telles que des fichiers CSV. Dans cette section, nous allons ajouter la capacité de créer des instances de la classe Structure à partir de lignes de données. Nous allons le faire en implémentant une méthode de classe from_row dans la classe Structure.

  1. Tout d'abord, vous devez ouvrir le fichier structure.py. C'est là que nous allons apporter des modifications à notre code. Utilisez la commande suivante dans votre terminal :
code ~/project/structure.py
  1. Ensuite, nous allons modifier la fonction validate_attributes. Cette fonction est un décorateur de classe qui extrait les instances de Validator et construit automatiquement les listes _fields et _types. Nous allons la mettre à jour pour collecter également les informations de type.
def validate_attributes(cls):
    """
    Class decorator that extracts Validator instances
    and builds the _fields and _types lists automatically
    """
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Set _types based on validator expected_types
    cls._types = [getattr(val, 'expected_type', lambda x: x) for val in validators]

    ## Create initialization method
    cls.create_init()

    return cls

Dans cette fonction mise à jour, nous collectons l'attribut expected_type de chaque validateur et le stockons dans la variable de classe _types. Cela sera utile plus tard lorsque nous convertirons les données des lignes en types appropriés.

  1. Maintenant, nous allons ajouter la méthode de classe from_row à la classe Structure. Cette méthode nous permettra de créer une instance de la classe à partir d'une ligne de données, qui peut être une liste ou un tuple.
@classmethod
def from_row(cls, row):
    """
    Create an instance from a data row (list or tuple)
    """
    rowdata = [func(val) for func, val in zip(cls._types, row)]
    return cls(*rowdata)

Voici comment cette méthode fonctionne :

  • Elle prend une ligne de données, qui peut être sous forme de liste ou de tuple.
  • Elle convertit chaque valeur de la ligne en le type attendu en utilisant la fonction correspondante de la liste _types.
  • Elle crée ensuite et retourne une nouvelle instance de la classe en utilisant les valeurs converties.
  1. Après avoir apporté ces modifications, enregistrez le fichier structure.py. Cela garantit que vos modifications de code sont conservées.

  2. Testons notre méthode from_row pour nous assurer qu'elle fonctionne comme prévu. Nous allons créer un test simple en utilisant la classe Stock. Exécutez la commande suivante dans votre terminal :

cd ~/project
python3 -c "from stock import Stock; s = Stock.from_row(['GOOG', '100', '490.1']); print(s); print(f'Cost: {s.cost}')"

Vous devriez voir une sortie similaire à celle-ci :

Stock('GOOG', 100, 490.1)
Cost: 49010.0

Notez que les valeurs sous forme de chaînes de caractères '100' et '490.1' ont été automatiquement converties en types appropriés (entier et flottant). Cela montre que notre méthode from_row fonctionne correctement.

  1. Enfin, essayons de lire des données à partir d'un fichier CSV en utilisant notre module reader.py. Exécutez la commande suivante dans votre terminal :
cd ~/project
python3 -c "from stock import Stock; import reader; portfolio = reader.read_csv_as_instances('portfolio.csv', Stock); print(portfolio); print(f'Total value: {sum(s.cost for s in portfolio)}')"

Vous devriez voir une sortie montrant les actions du fichier CSV :

[Stock('GOOG', 100, 490.1), Stock('AAPL', 50, 545.75), Stock('MSFT', 200, 30.47)]
Total value: 73444.0

La méthode from_row nous permet de convertir facilement les données CSV en instances de la classe Stock. Associée à la fonction read_csv_as_instances, elle constitue un moyen puissant de charger et de manipuler des données structurées.

✨ Vérifier la solution et pratiquer

Ajout de la validation des arguments de méthode

En Python, la validation des données est une partie importante de l'écriture de code robuste. Dans cette section, nous allons pousser notre validation plus loin en validant automatiquement les arguments des méthodes. Le fichier validate.py inclut déjà un décorateur @validated. Un décorateur en Python est une fonction spéciale qui peut modifier une autre fonction. Le décorateur @validated ici peut vérifier les arguments d'une fonction par rapport à leurs annotations. Les annotations en Python sont un moyen d'ajouter des métadonnées aux paramètres et aux valeurs de retour des fonctions.

Modifions notre code pour appliquer ce décorateur aux méthodes avec des annotations :

  1. Tout d'abord, nous devons comprendre comment le décorateur validated fonctionne. Ouvrez le fichier validate.py pour le réviser :
code ~/project/validate.py

Le décorateur validated utilise les annotations de fonction pour valider les arguments. Avant de permettre à la fonction de s'exécuter, il vérifie chaque argument par rapport à son type d'annotation. Par exemple, si un argument est annoté comme un entier, le décorateur s'assurera que la valeur passée est bien un entier.

  1. Maintenant, nous allons modifier la fonction validate_attributes dans structure.py pour envelopper les méthodes annotées avec le décorateur validated. Cela signifie que toute méthode avec des annotations dans la classe aura ses arguments automatiquement validés. Ouvrez le fichier structure.py :
code ~/project/structure.py
  1. Mettez à jour la fonction validate_attributes :
def validate_attributes(cls):
    """
    Class decorator that:
    1. Extracts Validator instances and builds _fields and _types lists
    2. Applies @validated decorator to methods with annotations
    """
    ## Import the validated decorator
    from validate import validated

    ## Process validator descriptors
    validators = []
    for name, val in vars(cls).items():
        if isinstance(val, Validator):
            validators.append(val)

    ## Set _fields based on validator names
    cls._fields = [val.name for val in validators]

    ## Set _types based on validator expected_types
    cls._types = [getattr(val, 'expected_type', lambda x: x) for val in validators]

    ## Apply @validated decorator to methods with annotations
    for name, val in vars(cls).items():
        if callable(val) and hasattr(val, '__annotations__'):
            setattr(cls, name, validated(val))

    ## Create initialization method
    cls.create_init()

    return cls

Cette fonction mise à jour fait maintenant les choses suivantes :

  1. Elle traite les descripteurs de validateurs comme avant. Les descripteurs de validateurs sont utilisés pour définir les règles de validation des attributs de classe.

  2. Elle trouve toutes les méthodes avec des annotations dans la classe. Les annotations sont ajoutées aux paramètres de méthode pour spécifier le type attendu de l'argument.

  3. Elle applique le décorateur @validated à ces méthodes. Cela garantit que les arguments passés à ces méthodes sont validés selon leurs annotations.

  4. Enregistrez le fichier après avoir apporté ces modifications. Enregistrer le fichier est important car cela assure que nos modifications sont stockées et peuvent être utilisées plus tard.

  5. Maintenant, mettons à jour la méthode sell dans la classe Stock pour inclure une annotation. Les annotations aident à spécifier le type attendu de l'argument, qui sera utilisé par le décorateur @validated pour la validation. Ouvrez le fichier stock.py :

code ~/project/stock.py
  1. Modifiez la méthode sell pour inclure une annotation de type :
## stock.py

from structure import Structure
from validate import String, PositiveInteger, PositiveFloat

class Stock(Structure):
    name = String()
    shares = PositiveInteger()
    price = PositiveFloat()

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

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

Le changement important est l'ajout de : PositiveInteger au paramètre nshares. Cela indique à Python (et à notre décorateur @validated) de valider cet argument en utilisant le validateur PositiveInteger. Ainsi, lorsque nous appelons la méthode sell, l'argument nshares doit être un entier positif.

  1. Exécutez les tests à nouveau pour vérifier que tout fonctionne toujours. Exécuter des tests est un bon moyen de nous assurer que nos modifications n'ont pas cassé une fonctionnalité existante.
cd ~/project
python3 teststock.py

Vous devriez voir tous les tests passer :

.........
----------------------------------------------------------------------
Ran 9 tests in 0.001s

OK
  1. Testons notre nouvelle validation d'arguments. Nous allons essayer d'appeler la méthode sell avec des arguments valides et invalides pour voir si la validation fonctionne comme prévu.
cd ~/project
python3 -c "from stock import Stock; s = Stock('GOOG', 100, 490.1); s.sell(25); print(s); try: s.sell(-25); except Exception as e: print(f'Error: {e}')"

Vous devriez voir une sortie similaire à :

Stock('GOOG', 75, 490.1)
Error: Bad Arguments
  nshares: must be >= 0

Cela montre que notre validation d'arguments de méthode fonctionne ! Le premier appel à sell(25) réussit car 25 est un entier positif. Mais le deuxième appel à sell(-25) échoue car -25 n'est pas un entier positif.

Vous avez maintenant implémenté un système complet pour :

  1. Valider les attributs de classe en utilisant des descripteurs. Les descripteurs sont utilisés pour définir les règles de validation des attributs de classe.
  2. Collecter automatiquement les informations de champ en utilisant des décorateurs de classe. Les décorateurs de classe peuvent modifier le comportement d'une classe, comme collecter les informations de champ.
  3. Convertir les données de ligne en instances. Cela est utile lorsque vous travaillez avec des données provenant de sources externes.
  4. Valider les arguments de méthode en utilisant des annotations. Les annotations aident à spécifier le type attendu de l'argument pour la validation.

Cela démontre la puissance de combiner les descripteurs et les décorateurs en Python pour créer des classes expressives et auto - validantes.

✨ Vérifier la solution et pratiquer

Résumé

Dans ce laboratoire (lab), vous avez appris à combiner les fonctionnalités puissantes de Python pour créer un code propre et auto - validant. Vous avez maîtrisé des concepts clés tels que l'utilisation de descripteurs pour la validation d'attributs, la création de décorateurs de classe pour l'automatisation de la génération de code et l'application automatique de décorateurs par héritage.

Ces techniques sont des outils puissants pour créer un code Python robuste et maintenable. Elles vous permettent d'exprimer clairement les exigences de validation et de les appliquer dans toute votre base de code. Vous pouvez maintenant appliquer ces modèles dans vos propres projets Python pour améliorer la qualité du code et réduire le code répétitif (boilerplate code).