Comment vérifier si une fonction est un générateur en Python

PythonPythonBeginner
Pratiquer maintenant

💡 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 apprendrez à identifier les fonctions génératrices (generator functions) en Python et à comprendre les différences fondamentales entre les fonctions ordinaires et les générateurs. Cette connaissance est essentielle pour écrire un code efficace et économisant en mémoire, en particulier lorsqu'il s'agit de traiter de grands ensembles de données ou des séquences infinies.

Le laboratoire vous guidera dans la différenciation entre les fonctions et les générateurs, en vérifiant leur type à l'aide de inspect.isgeneratorfunction et en testant la présence du mot - clé yield. Vous créerez un script Python pour illustrer les différences, en observant comment les fonctions retournent un résultat complet tandis que les générateurs produisent des valeurs de manière itérative, en mettant en pause et en reprenant l'exécution au besoin.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("Python")) -.-> python/FunctionsGroup(["Functions"]) python(("Python")) -.-> python/ModulesandPackagesGroup(["Modules and Packages"]) python(("Python")) -.-> python/AdvancedTopicsGroup(["Advanced Topics"]) python/FunctionsGroup -.-> python/function_definition("Function Definition") python/ModulesandPackagesGroup -.-> python/standard_libraries("Common Standard Libraries") python/AdvancedTopicsGroup -.-> python/generators("Generators") subgraph Lab Skills python/function_definition -.-> lab-559519{{"Comment vérifier si une fonction est un générateur en Python"}} python/standard_libraries -.-> lab-559519{{"Comment vérifier si une fonction est un générateur en Python"}} python/generators -.-> lab-559519{{"Comment vérifier si une fonction est un générateur en Python"}} end

Différencier les fonctions et les générateurs

Dans cette étape, vous apprendrez les principales différences entre les fonctions Python ordinaires et les générateurs. Comprendre cette distinction est essentiel pour écrire un code efficace et économisant en mémoire, en particulier lorsqu'il s'agit de traiter de grands ensembles de données ou des séquences infinies.

Fonctions :

Une fonction est un bloc de code qui effectue une tâche spécifique. Lorsqu'une fonction est appelée, elle exécute son code, effectue éventuellement des calculs et retourne une valeur (ou None si aucune instruction return explicite n'est présente). L'état de la fonction n'est pas conservé entre les appels.

Générateurs :

Un générateur est un type spécial de fonction qui utilise le mot - clé yield au lieu de return. Lorsqu'un générateur est appelé, il retourne un objet itérateur. Chaque fois que vous demandez une valeur à l'itérateur, le générateur s'exécute jusqu'à ce qu'il rencontre une instruction yield. Le générateur se met alors en pause, sauvegarde son état et produit la valeur. La prochaine fois qu'une valeur est demandée, le générateur reprend là où il s'est arrêté.

Illustrons cela avec un exemple. Tout d'abord, créez un fichier nommé function_vs_generator.py dans votre répertoire ~/project en utilisant l'éditeur VS Code.

## ~/project/function_vs_generator.py

## Fonction ordinaire
def square_numbers_function(numbers):
    result = []
    for number in numbers:
        result.append(number * number)
    return result

## Fonction génératrice
def square_numbers_generator(numbers):
    for number in numbers:
        yield number * number

## Utilisation exemple
numbers = [1, 2, 3, 4, 5]

## Utilisation de la fonction
function_result = square_numbers_function(numbers)
print("Function Result:", function_result)

## Utilisation du générateur
generator_result = square_numbers_generator(numbers)
print("Generator Result:", list(generator_result)) ## Convertir le générateur en liste pour l'impression

Maintenant, exécutez le script Python :

python ~/project/function_vs_generator.py

Vous devriez voir la sortie suivante :

Function Result: [1, 4, 9, 16, 25]
Generator Result: [1, 4, 9, 16, 25]

La fonction et le générateur produisent le même résultat. Cependant, la principale différence réside dans la façon dont ils l'obtiennent. La fonction calcule tous les carrés et les stocke dans une liste avant de retourner. Le générateur, en revanche, produit chaque carré un par un, seulement lorsqu'il est demandé.

Pour illustrer davantage la différence, modifions le script pour afficher le type de l'objet retourné :

## ~/project/function_vs_generator.py

## Fonction ordinaire
def square_numbers_function(numbers):
    result = []
    for number in numbers:
        result.append(number * number)
    return result

## Fonction génératrice
def square_numbers_generator(numbers):
    for number in numbers:
        yield number * number

## Utilisation exemple
numbers = [1, 2, 3, 4, 5]

## Utilisation de la fonction
function_result = square_numbers_function(numbers)
print("Function Result Type:", type(function_result))

## Utilisation du générateur
generator_result = square_numbers_generator(numbers)
print("Generator Result Type:", type(generator_result))

Exécutez le script à nouveau :

python ~/project/function_vs_generator.py

La sortie sera :

Function Result Type: <class 'list'>
Generator Result Type: <class 'generator'>

Cela montre clairement que la fonction retourne une list, tandis que le générateur retourne un objet generator. Les générateurs sont économes en mémoire car ils ne stockent pas toutes les valeurs en mémoire à la fois. Ils génèrent les valeurs à la demande.

Vérifier le type avec inspect.isgeneratorfunction

Dans l'étape précédente, vous avez appris la différence de base entre les fonctions et les générateurs. Maintenant, explorons comment déterminer de manière programmée si une fonction est une fonction génératrice (generator function) en utilisant la méthode inspect.isgeneratorfunction(). Cela est particulièrement utile lorsque vous travaillez avec du code où vous ne connaissez peut - être pas les détails de l'implémentation d'une fonction.

Le module inspect en Python fournit des outils pour l'introspection, ce qui signifie examiner les caractéristiques internes d'objets tels que des fonctions, des classes, des modules, etc. La méthode inspect.isgeneratorfunction() vérifie spécifiquement si un objet donné est une fonction génératrice.

Modifions le fichier function_vs_generator.py dans votre répertoire ~/project pour inclure cette vérification. Ouvrez le fichier dans VS Code et ajoutez le code suivant :

## ~/project/function_vs_generator.py

import inspect

## Fonction ordinaire
def square_numbers_function(numbers):
    result = []
    for number in numbers:
        result.append(number * number)
    return result

## Fonction génératrice
def square_numbers_generator(numbers):
    for number in numbers:
        yield number * number

## Vérifier si c'est une fonction génératrice
print("Is square_numbers_function a generator function?", inspect.isgeneratorfunction(square_numbers_function))
print("Is square_numbers_generator a generator function?", inspect.isgeneratorfunction(square_numbers_generator))

Dans ce code, nous importons d'abord le module inspect. Ensuite, nous utilisons inspect.isgeneratorfunction() pour vérifier à la fois square_numbers_function et square_numbers_generator.

Maintenant, exécutez le script Python :

python ~/project/function_vs_generator.py

Vous devriez voir la sortie suivante :

Is square_numbers_function a generator function? False
Is square_numbers_generator a generator function? True

Cela confirme que inspect.isgeneratorfunction() identifie correctement la fonction génératrice.

Cette méthode est très utile lorsque vous avez besoin de traiter les fonctions différemment en fonction de si elles sont des générateurs ou des fonctions ordinaires. Par exemple, vous pourriez vouloir itérer sur les résultats d'un générateur, mais simplement appeler une fonction ordinaire.

Tester l'utilisation du mot - clé yield

Dans cette étape, nous allons nous concentrer sur la façon dont la présence du mot - clé yield définit fondamentalement une fonction génératrice. Une fonction est considérée comme un générateur si et seulement si elle contient au moins une instruction yield. Créons un test simple pour confirmer cela.

Ouvrez le fichier function_vs_generator.py dans votre répertoire ~/project en utilisant VS Code. Nous allons ajouter une fonction qui n'utilise pas yield et voir comment elle se comporte lorsqu'elle est traitée comme un potentiel générateur.

## ~/project/function_vs_generator.py

import inspect

## Fonction ordinaire
def square_numbers_function(numbers):
    result = []
    for number in numbers:
        result.append(number * number)
    return result

## Fonction génératrice
def square_numbers_generator(numbers):
    for number in numbers:
        yield number * number

## Fonction qui retourne une liste, pas un générateur
def return_list(numbers):
    return [x for x in numbers]

## Vérifier si c'est une fonction génératrice
print("Is square_numbers_function a generator function?", inspect.isgeneratorfunction(square_numbers_function))
print("Is square_numbers_generator a generator function?", inspect.isgeneratorfunction(square_numbers_generator))
print("Is return_list a generator function?", inspect.isgeneratorfunction(return_list))

Dans ce code mis à jour, nous avons ajouté une fonction return_list qui retourne simplement une liste en utilisant une compréhension de liste. Elle ne contient pas le mot - clé yield. Nous utilisons ensuite inspect.isgeneratorfunction() pour vérifier si return_list est une fonction génératrice.

Maintenant, exécutez le script Python :

python ~/project/function_vs_generator.py

Vous devriez voir la sortie suivante :

Is square_numbers_function a generator function? False
Is square_numbers_generator a generator function? True
Is return_list a generator function? False

Comme prévu, return_list n'est pas identifiée comme une fonction génératrice car elle n'utilise pas le mot - clé yield. Cela démontre que le mot - clé yield est essentiel pour définir un générateur en Python. Sans lui, la fonction se comporte comme une fonction ordinaire, retournant une valeur (ou None) et ne conservant pas son état entre les appels.

Résumé

Dans ce laboratoire, vous avez appris les différences fondamentales entre les fonctions Python ordinaires et les générateurs. Les fonctions exécutent un bloc de code et retournent une valeur, tandis que les générateurs, en utilisant le mot - clé yield, retournent un objet itérateur qui produit des valeurs à la demande, en mettant en pause et en sauvegardant leur état entre les appels.

Vous avez exploré comment les générateurs sont économes en mémoire, en particulier lorsqu'ils traitent de grands ensembles de données, car ils génèrent des valeurs une par une au lieu de les stocker toutes en mémoire comme le font les fonctions. Le laboratoire a démontré cette différence à travers un exemple pratique de calcul du carré de nombres en utilisant à la fois une fonction et un générateur.