Utilisation et bonnes pratiques – Real Python

By | septembre 28, 2020

Cours Python en ligne

Le Python revenir L'instruction est un élément clé des fonctions et des méthodes. Vous pouvez utiliser le revenir pour que vos fonctions renvoient des objets Python au code de l'appelant. Ces objets sont connus sous le nom de fonction valeur de retour. Vous pouvez les utiliser pour effectuer des calculs supplémentaires dans vos programmes.

En utilisant le revenir La déclaration est effectivement une compétence de base si vous souhaitez coder des fonctions personnalisées qui sont pythoniques et robustes.

Dans ce didacticiel, vous apprendrez:

  • Comment utiliser le Python revenir déclaration dans vos fonctions
  • Comment retourner Célibataire ou valeurs multiples de vos fonctions
  • Quoi les meilleures pratiques à observer lors de l'utilisation revenir déclarations

Avec ces connaissances, vous serez en mesure d'écrire des fonctions plus lisibles, maintenables et concises en Python. Si vous êtes totalement nouveau dans les fonctions Python, vous pouvez consulter Définir votre propre fonction Python avant de plonger dans ce didacticiel.

Premiers pas avec les fonctions Python

La plupart des langages de programmation vous permettent d'attribuer un nom à un bloc de code qui effectue un calcul concret. Ces blocs de code nommés peuvent être réutilisés rapidement car vous pouvez utiliser leur nom pour les appeler à partir de différents endroits de votre code.

Les programmeurs appellent ces blocs de code nommés sous-programmes, routines, procédures, ou les fonctions selon la langue qu'ils utilisent. Dans certaines langues, il existe une nette différence entre une routine ou une procédure et une fonction.

Parfois, cette différence est si forte que vous devez utiliser un mot-clé spécifique pour définir une procédure ou un sous-programme et un autre mot-clé pour définir une fonction. Par exemple, le langage de programmation Visual Basic utilise Sous et Une fonction faire la différence entre les deux.

En général, un procédure est un bloc de code nommé qui effectue un ensemble d'actions sans calculer une valeur ou un résultat final. D'autre part, un une fonction est un bloc de code nommé qui effectue certaines actions dans le but de calculer une valeur finale ou un résultat, qui est ensuite renvoyé au code de l'appelant. Les procédures et les fonctions peuvent agir sur un ensemble de valeurs d'entrée, mieux connu sous le nom de arguments.

En Python, ces types de blocs de code nommés sont appelés fonctions car ils renvoient toujours une valeur à l'appelant. La documentation Python définit une fonction comme suit:

Une série d'instructions qui renvoie une valeur à un appelant. Il peut également être passé zéro ou plusieurs arguments qui peuvent être utilisés dans l'exécution du corps. (La source)

Même si la documentation officielle indique qu’une fonction «renvoie une valeur à l’appelant», vous verrez bientôt que les fonctions peuvent renvoyer n’importe quel objet Python au code de l’appelant.

En général, une fonction prend arguments (le cas échéant), exécute certaines opérations, et Retour une valeur (ou un objet). La valeur qu’une fonction renvoie à l’appelant est généralement appelée fonction valeur de retour. Toutes les fonctions Python ont une valeur de retour, explicite ou implicite. Vous découvrirez la différence entre les valeurs de retour explicites et implicites plus loin dans ce didacticiel.

Pour écrire une fonction Python, vous avez besoin d'un entête qui commence par le def mot-clé, suivi du nom de la fonction, d'une liste facultative d'arguments séparés par des virgules à l'intérieur d'une paire de parenthèses obligatoires et d'un deux-points final.

Le deuxième composant d'une fonction est son bloc de code, ou corps. Python définit les blocs de code en utilisant l'indentation au lieu de crochets, commencer et fin mots-clés, etc. Ainsi, pour définir une fonction en Python, vous pouvez utiliser la syntaxe suivante:

def nom_fonction(arg1, arg2,..., argN):
    # Le code de la fonction va ici ...
    passer

Lorsque vous codez une fonction Python, vous devez définir un en-tête avec le def mot-clé, le nom de la fonction et une liste d'arguments entre parenthèses. Notez que la liste d'arguments est facultative, mais que les parenthèses sont syntaxiquement obligatoires. Ensuite, vous devez définir le bloc de code de la fonction, qui commencera un niveau d'indentation vers la droite.

Dans l'exemple ci-dessus, vous utilisez un passer déclaration. Ce type d'instruction est utile lorsque vous avez besoin d'une instruction d'espace réservé dans votre code pour le rendre syntaxiquement correct, mais que vous n'avez aucune action à effectuer. passer les déclarations sont également connues sous le nom de opération nulle car ils n'effectuent aucune action.

Pour utiliser une fonction, vous devez l'appeler. Un appel de fonction se compose du nom de la fonction suivi des arguments de la fonction entre parenthèses:

nom_fonction(arg1, arg2, ..., argN)

Vous n'aurez besoin de transmettre des arguments à un appel de fonction que si la fonction en a besoin. Les parenthèses, en revanche, sont toujours obligatoires dans un appel de fonction. Si vous les oubliez, vous n’appelerez pas la fonction mais vous la référencerez comme un objet fonction.

Pour que vos fonctions renvoient une valeur, vous devez utiliser le Python revenir déclaration. C’est ce que vous allez aborder à partir de maintenant.

Comprendre le Python revenir Déclaration

le Python revenir déclaration est une instruction spéciale que vous pouvez utiliser dans une fonction ou une méthode pour renvoyer le résultat de la fonction à l'appelant. UNE revenir l'instruction se compose du revenir mot-clé suivi d'une option valeur de retour.

La valeur de retour d'une fonction Python peut être n'importe quel objet Python. Tout en Python est un objet. Ainsi, vos fonctions peuvent renvoyer des valeurs numériques (int, flotte, et complexe valeurs), des collections et des séquences d'objets (liste, tuple, dictionnaire, ou ensemble objets), des objets définis par l'utilisateur, des classes, des fonctions et même des modules ou des packages.

Vous pouvez omettre la valeur de retour d'une fonction et utiliser un simple revenir sans valeur de retour. Vous pouvez également omettre l'intégralité revenir déclaration. Dans les deux cas, la valeur de retour sera Aucun.

Dans les deux sections suivantes, vous aborderez les bases de la revenir fonctionne et comment vous pouvez l'utiliser pour renvoyer le résultat de la fonction au code de l'appelant.

Explicite revenir Déclarations

Un explicite revenir déclaration met immédiatement fin à l'exécution d'une fonction et renvoie la valeur de retour au code de l'appelant. Pour ajouter un explicite revenir instruction à une fonction Python, vous devez utiliser revenir suivi d'une valeur de retour facultative:

>>>

>>> def return_42():
...     revenir 42  # Une déclaration de retour explicite
...

>>> return_42()  # Le code de l'appelant obtient 42
42

Lorsque vous définissez return_42 (), vous ajoutez un explicite revenir déclaration (retour 42) à la fin du bloc de code de la fonction. 42 est la valeur de retour explicite de return_42 (). Cela signifie que chaque fois que vous appelez return_42 (), la fonction enverra 42 retour à l'appelant.

Si vous définissez une fonction avec un revenir instruction qui a une valeur de retour explicite, vous pouvez alors utiliser cette valeur de retour dans n'importe quelle expression:

>>>

>>> num = return_42()
>>> num
42

>>> return_42() * 2
84

>>> return_42() + 5
47

Puisque return_42 () renvoie une valeur numérique, vous pouvez utiliser cette valeur dans une expression mathématique ou tout autre type d'expression dans lequel la valeur a une signification logique ou cohérente. C'est ainsi qu'un code appelant peut tirer parti de la valeur de retour d'une fonction.

Notez que vous pouvez utiliser un revenir instruction uniquement dans une définition de fonction ou de méthode. Si vous l'utilisez ailleurs, vous obtiendrez un Erreur de syntaxe:

>>>

>>> revenir 42
  Fichier "", ligne 1
Erreur de syntaxe: fonction extérieure 'return'

Lorsque vous utilisez revenir en dehors d'une fonction ou d'une méthode, vous obtenez un Erreur de syntaxe vous indiquant que l'instruction ne peut pas être utilisée en dehors d'une fonction.

Vous pouvez utiliser n'importe quel objet Python comme valeur de retour. Puisque tout dans Python est un objet, vous pouvez renvoyer des chaînes, des listes, des tuples, des dictionnaires, des fonctions, des classes, des instances, des objets définis par l'utilisateur et même des modules ou des packages.

Par exemple, disons que vous devez écrire une fonction qui prend une liste d'entiers et renvoie une liste contenant uniquement les nombres pairs de la liste d'origine. Voici une façon de coder cette fonction:

>>>

>>> def obtenir encore(Nombres):
...     even_nums = [[[[num pour num dans Nombres si ne pas num % 2]
...     revenir even_nums
...

>>> obtenir encore([[[[1, 2, 3, 4, 5, 6])
[2, 4, 6]

obtenir encore() utilise une compréhension de liste pour créer une liste qui filtre les nombres impairs dans l'original Nombres. Ensuite, la fonction renvoie la liste résultante, qui ne contient que des nombres pairs.

Une pratique courante consiste à utiliser le résultat d'une expression comme valeur de retour dans un revenir déclaration. Pour appliquer cette idée, vous pouvez réécrire obtenir encore() comme suit:

>>>

>>> def obtenir encore(Nombres):
...     revenir [[[[num pour num dans Nombres si ne pas num % 2]
...

>>> obtenir encore([[[[1, 2, 3, 4, 5, 6])
[2, 4, 6]

La compréhension de la liste est évaluée, puis la fonction retourne avec la liste résultante. Notez que vous ne pouvez utiliser des expressions que dans un revenir déclaration. Les expressions sont différentes des instructions telles que les conditions ou les boucles.

Pour un autre exemple, disons que vous devez calculer la moyenne d'un échantillon de valeurs numériques. Pour ce faire, vous devez diviser la somme des valeurs par le nombre de valeurs. Voici un exemple qui utilise les fonctions intégrées somme() et len ():

>>>

>>> def signifier(échantillon):
...     revenir somme(échantillon) / len(échantillon)
...

>>> signifier([[[[1, 2, 3, 4])
2,5

Dans signifier(), vous n'utilisez pas de variable locale pour stocker le résultat du calcul. Au lieu de cela, vous utilisez l'expression directement comme valeur de retour. Python évalue d'abord l'expression sum (échantillon) / len (échantillon) puis renvoie le résultat de l'évaluation, qui dans ce cas est la valeur 2,5.

Implicite revenir Déclarations

Une fonction Python aura toujours une valeur de retour. Il n'y a pas de notion de procédure ou de routine en Python. Donc, si vous n'utilisez pas explicitement une valeur de retour dans un revenir déclaration, ou si vous omettez totalement revenir instruction, Python renverra implicitement une valeur par défaut pour vous. Cette valeur de retour par défaut sera toujours Aucun.

Supposons que vous écrivez une fonction qui ajoute 1 à un certain nombre X, mais vous oubliez de fournir un revenir déclaration. Dans ce cas, vous obtiendrez un implicite revenir déclaration qui utilise Aucun comme valeur de retour:

>>>

>>> def ajoute un(X):
...     # Aucune déclaration de retour du tout
...     résultat = X + 1
...

>>> valeur = ajoute un(5)
>>> valeur

>>> impression(valeur)
Aucun

Si vous ne fournissez pas de contenu explicite revenir instruction avec une valeur de retour explicite, alors Python fournira un implicite revenir instruction utilisant Aucun comme valeur de retour. Dans l'exemple ci-dessus, ajoute un() ajoute 1 à X et stocke la valeur dans résultat mais ça ne revient pas résultat. C’est pourquoi vous obtenez value = Aucun au lieu de valeur = 6. Pour résoudre le problème, vous devez soit résultat de retour ou directement retour x + 1.

Un exemple de fonction qui renvoie Aucun est impression(). Le but de cette fonction est d'imprimer des objets dans un fichier de flux de texte, qui est normalement la sortie standard (votre écran). Donc, cette fonction n'a pas besoin d'un explicite revenir car elle ne renvoie rien d'utile ou de significatif:

>>>

>>> return_value = impression("Bonjour le monde")
Bonjour le monde

>>> impression(return_value)
Aucun

L'appel à impression() impressions Bonjour le monde à l'écran. Puisque c'est le but de impression(), la fonction n'a pas besoin de renvoyer quoi que ce soit d'utile, donc vous obtenez Aucun comme valeur de retour.

Quelle que soit la durée et la complexité de vos fonctions, toute fonction sans revenir déclaration, ou une avec un revenir instruction sans valeur de retour, retournera Aucun.

Retour vs impression

Si vous travaillez dans une session interactive, vous pourriez penser que l’impression d’une valeur et le renvoi d’une valeur sont des opérations équivalentes. Considérez les deux fonctions suivantes et leur sortie:

>>>

>>> def print_greeting():
...     impression("Bonjour le monde")
...

>>> print_greeting()
Bonjour le monde

>>> def return_greeting():
...     revenir "Bonjour le monde"
...

>>> return_greeting()
'Bonjour le monde'

Les deux fonctions semblent faire la même chose. Dans les deux cas, vous voyez Bonjour le monde imprimé sur votre écran. Il n’ya qu’une subtile différence visible: les guillemets simples dans le deuxième exemple. Mais regardez ce qui se passe si vous retournez un autre type de données, disons int objet:

>>>

>>> def print_42():
...     impression(42)
...

>>> print_42()
42

>>> def return_42():
...     revenir 42
...

>>> return_42()
42

Il n'y a plus de différence visible maintenant. Dans les deux cas, vous pouvez voir 42 sur votre écran. Ce comportement peut être déroutant si vous ne faites que commencer avec Python. Vous pourriez penser que renvoyer et imprimer une valeur sont des actions équivalentes.

Maintenant, supposons que vous approfondissiez Python et que vous commenciez à écrire votre premier script. Vous ouvrez un éditeur de texte et tapez le code suivant:

    1 def ajouter(une, b):
    2     résultat = une + b
    3     revenir résultat
    4 
    5 ajouter(2, 2)

ajouter() prend deux nombres, les ajoute et renvoie le résultat. Sur ligne 5, tu appelles ajouter() résumer 2 plus 2. Puisque vous êtes toujours en train d'apprendre la différence entre renvoyer et imprimer une valeur, vous pouvez vous attendre à ce que votre script s'imprime 4 à l'écran. Cependant, ce n’est pas ce qui se passe et vous n’avez rien sur votre écran.

Essayez-le par vous-même. Enregistrez votre script dans un fichier appelé ajoutant.py et exécutez-le à partir de votre ligne de commande comme suit:

Si vous courez ajoutant.py à partir de votre ligne de commande, vous ne verrez aucun résultat sur votre écran. En effet, lorsque vous exécutez un script, les valeurs de retour des fonctions que vous appelez dans le script ne sont pas affichées à l’écran comme elles le font dans une session interactive.

Si vous voulez que votre script affiche le résultat de l'appel ajouter() sur votre écran, vous devez appeler explicitement impression(). Découvrez la mise à jour suivante de ajoutant.py:

    1 def ajouter(une, b):
    2     résultat = une + b
    3     revenir résultat
    4 
    5 impression(ajouter(2, 2))

Maintenant, quand tu cours ajoutant.py, vous verrez le numéro 4 sur votre écran.

Ainsi, si vous travaillez dans une session interactive, Python affichera le résultat de tout appel de fonction directement sur votre écran. Mais si vous écrivez un script et que vous souhaitez voir la valeur de retour d'une fonction, vous devez utiliser explicitement impression().

Renvoyer plusieurs valeurs

Vous pouvez utiliser un revenir instruction pour renvoyer plusieurs valeurs à partir d'une fonction. Pour ce faire, il vous suffit de fournir plusieurs valeurs de retour séparées par des virgules.

Par exemple, supposons que vous deviez écrire une fonction qui prend un échantillon de données numériques et renvoie un résumé des mesures statistiques. Pour coder cette fonction, vous pouvez utiliser le module standard Python statistiques, qui fournit plusieurs fonctions pour calculer les statistiques mathématiques des données numériques.

Voici une implémentation possible de votre fonction:

importer statistiques comme st

def décris(échantillon):
    revenir st.signifier(échantillon), st.médian(échantillon), st.mode(échantillon)

Dans décris(), vous profitez de la capacité de Python à renvoyer plusieurs valeurs en une seule revenir en renvoyant la moyenne, la médiane et le mode de l'échantillon en même temps. Notez que, pour renvoyer plusieurs valeurs, il vous suffit de les écrire dans une liste séparée par des virgules dans l'ordre dans lequel vous voulez qu'elles soient renvoyées.

Une fois que vous avez codé décris(), vous pouvez profiter d'une puissante fonctionnalité Python connue sous le nom de décompression itérable pour décompresser les trois mesures en trois variables séparées, ou vous pouvez simplement tout stocker dans une variable:

>>>

>>> échantillon = [[[[dix, 2, 4, 7, 9, 3, 9, 8, 6, 7]
>>> signifier, médian, mode = décris(échantillon)

>>> signifier
6,5

>>> médian
7,0

>>> mode
7

>>> desc = décris(échantillon)
>>> desc
(6,5, 7,0, 7)

>>> type(desc)

Ici, vous décompressez les trois valeurs de retour de décris() dans les variables signifier, médian, et mode. Notez que dans le dernier exemple, vous stockez toutes les valeurs dans une seule variable, desc, qui s'avère être un Python tuple.

La fonction intégrée divmod () est également un exemple de fonction qui renvoie plusieurs valeurs. La fonction prend deux nombres (non complexes) comme arguments et renvoie deux nombres, le quotient des deux valeurs d'entrée et le reste de la division:

>>>

>>> divmod(15, 3)
(5, 0)

>>> divmod(8, 3)
(2, 2)

L'appel à divmod () renvoie un tuple contenant le quotient et le reste résultant de la division des deux nombres non complexes fournis comme arguments. Ceci est un exemple de fonction avec plusieurs valeurs de retour.

Utiliser le Python revenir Énoncé: meilleures pratiques

Jusqu'à présent, vous avez couvert les bases de la façon dont le Python revenir déclaration fonctionne. Vous savez maintenant écrire des fonctions qui renvoient une ou plusieurs valeurs à l'appelant. De plus, vous avez appris que si vous n’ajoutez pas de contenu explicite revenir avec une valeur de retour explicite à une fonction donnée, puis Python l'ajoutera pour vous. Cette valeur sera Aucun.

Dans cette section, vous aborderez plusieurs exemples qui vous guideront à travers un ensemble de bonnes pratiques de programmation pour utiliser efficacement le revenir déclaration. Ces pratiques vous aideront à écrire des fonctions plus lisibles, maintenables, robustes et efficaces en Python.

Retour Aucun Explicitement

Certains programmeurs s'appuient sur l'implicite revenir instruction que Python ajoute à toute fonction sans une fonction explicite. Cela peut être déroutant pour les développeurs qui viennent d'autres langages de programmation dans lesquels une fonction sans valeur de retour est appelée un procédure.

Il existe des situations dans lesquelles vous pouvez ajouter un retour Aucun à vos fonctions. Dans d'autres situations, cependant, vous pouvez vous fier au comportement par défaut de Python:

  • Si votre fonction effectue des actions mais n’a pas de message clair et utile revenir value, alors vous pouvez omettre de retourner Aucun parce que faire cela serait tout simplement superflu et déroutant. Vous pouvez également utiliser un nu revenir sans valeur de retour juste pour indiquer clairement votre intention de revenir de la fonction.

  • Si votre fonction a plusieurs revenir déclarations et retour Aucun est une option valide, alors vous devriez envisager l'utilisation explicite de retour Aucun au lieu de se fier au comportement par défaut de Python.

Ces pratiques peuvent améliorer la lisibilité et la maintenabilité de votre code en communiquant explicitement votre intention.

Quand il s'agit de revenir Aucun, vous pouvez utiliser l'une des trois approches possibles:

  1. Omettez le revenir et s'appuyer sur le comportement par défaut de retour Aucun.
  2. Utilisez un nu revenir sans valeur de retour, qui renvoie également Aucun.
  3. Revenir Aucun explicitement.

Voici comment cela fonctionne dans la pratique:

>>>

>>> def omit_return_stmt():
...     # Omettre l'instruction de retour
...     passer
...
>>> impression(omit_return_stmt())
Aucun

>>> def retour_nu():
...     # Utilisez un simple retour
...     revenir
...
>>> impression(retour_nu())
Aucun

>>> def return_none_explicitly():
...     # Renvoyer Aucun explicitement
...     revenir Aucun
...
>>> impression(return_none_explicitly())
Aucun

Retour ou non Aucun est explicitement une décision personnelle. Cependant, vous devez considérer que dans certains cas, un retour Aucun peut éviter les problèmes de maintenabilité. Cela est particulièrement vrai pour les développeurs qui viennent d'autres langages de programmation qui ne se comportent pas comme Python.

Se souvenir de la valeur de retour

Lors de l'écriture de fonctions personnalisées, vous pouvez accidentellement oublier de renvoyer une valeur à partir d'une fonction. Dans ce cas, Python retournera Aucun pour toi. Cela peut provoquer des bogues subtils qui peuvent être difficiles à comprendre et à déboguer pour un développeur Python débutant.

Vous pouvez éviter ce problème en écrivant le revenir instruction immédiatement après l'en-tête de la fonction. Ensuite, vous pouvez effectuer une deuxième passe pour écrire le corps de la fonction. Voici un modèle que vous pouvez utiliser lors du codage de vos fonctions Python:

def template_func(args):
    résultat = 0  # Initialiser la valeur de retour
    # Votre code va ici ...
    revenir résultat  # Renvoie explicitement le résultat

Si vous vous habituez à démarrer vos fonctions de cette manière, il y a de fortes chances que vous ne manquiez plus le revenir déclaration. Avec cette approche, vous pouvez écrire le corps de la fonction, le tester et renommer les variables une fois que vous savez que la fonction fonctionne.

Cette pratique peut augmenter votre productivité et rendre vos fonctions moins sujettes aux erreurs. Cela peut également vous faire gagner beaucoup de temps lors du débogage.

Éviter les expressions complexes

Comme vous l'avez vu précédemment, il est courant d'utiliser le résultat d'une expression comme valeur de retour dans les fonctions Python. Si l'expression que vous utilisez devient trop complexe, cette pratique peut conduire à des fonctions difficiles à comprendre, déboguer et gérer.

Par exemple, si vous effectuez un calcul complexe, il serait plus lisible de calculer de manière incrémentielle le résultat final en utilisant variables temporaires avec des noms significatifs.

Considérez la fonction suivante qui calcule la variance d'un échantillon de données numériques:

>>>

>>> def variance(Les données, ddof=0):
...     signifier = somme(Les données) / len(Les données)
...     revenir somme((X - signifier) ** 2 pour X dans Les données) / (len(Les données) - ddof)
...

>>> variance([[[[3, 4, 7, 5, 6, 2, 9, 4, 1, 3])
5,24

L'expression que vous utilisez ici est assez complexe et difficile à comprendre. Il est également difficile à déboguer car vous effectuez plusieurs opérations dans une seule expression. Pour contourner ce problème particulier, vous pouvez tirer parti d'une approche de développement incrémentiel qui améliore la lisibilité de la fonction.

Jetez un œil à la mise en œuvre alternative suivante de variance():

>>>

>>> def variance(Les données, ddof=0):
...     n = len(Les données)
...     signifier = somme(Les données) / n
...     total_square_dev = somme((X - signifier) ** 2 pour X dans Les données)
...     revenir total_square_dev / (n - ddof)
...

>>> variance([[[[3, 4, 7, 5, 6, 2, 9, 4, 1, 3])
5,24

Dans cette seconde implémentation de variance(), vous calculez la variance en plusieurs étapes. Chaque étape est représentée par une variable temporaire avec un nom significatif.

Variables temporaires comme n, signifier, et total_square_dev sont souvent utiles pour déboguer votre code. Si, par exemple, quelque chose ne va pas avec l'un d'entre eux, vous pouvez appeler impression() pour savoir ce qui se passe avant le revenir l'instruction s'exécute.

En général, vous devez éviter d'utiliser des expressions complexes dans votre revenir déclaration. Au lieu de cela, vous pouvez diviser votre code en plusieurs étapes et utiliser des variables temporaires pour chaque étape. L'utilisation de variables temporaires peut faciliter le débogage, la compréhension et la maintenance de votre code.

Renvoyer des valeurs vs modifier des globaux

Les fonctions qui n'ont pas de revenir instruction avec une valeur de retour significative préforme souvent des actions qui ont des effets secondaires. UNE effet secondaire peut être, par exemple, imprimer quelque chose à l'écran, modifier une variable globale, mettre à jour l'état d'un objet, écrire du texte dans un fichier, etc.

La modification des variables globales est généralement considérée comme une mauvaise pratique de programmation. Tout comme les programmes avec des expressions complexes, les programmes qui modifient les variables globales peuvent être difficiles à déboguer, à comprendre et à maintenir.

Lorsque vous modifiez une variable globale, vous affectez potentiellement toutes les fonctions, classes, objets et toutes les autres parties de vos programmes qui reposent sur cette variable globale.

Pour comprendre un programme qui modifie des variables globales, vous devez être conscient de toutes les parties du programme qui peuvent voir, accéder et modifier ces variables. Donc, les bonnes pratiques recommandent d'écrire fonctions autonomes qui prennent certains arguments et renvoient une ou plusieurs valeurs utiles sans provoquer d'effet secondaire sur les variables globales.

De plus, les fonctions avec un revenir Les instructions qui renvoient une valeur significative sont plus faciles à tester que les fonctions qui modifient ou mettent à jour des variables globales.

L'exemple suivant montre une fonction qui modifie une variable globale. La fonction utilise le global déclaration, qui est également considérée comme une mauvaise pratique de programmation en Python:

>>>

>>> compteur = 0

>>> def incrément():
...     global compteur
...     compteur + = 1
...

>>> incrément()
>>> compteur
1

Dans cet exemple, vous créez d'abord une variable globale, compteur, avec une valeur initiale de 0. À l'intérieur incrément(), vous utilisez un global pour indiquer à la fonction que vous souhaitez modifier une variable globale. La dernière instruction s'incrémente compteur par 1.

Le résultat de l'appel incrément() dépendra de la valeur initiale de compteur. Différentes valeurs initiales pour compteur générera des résultats différents, de sorte que le résultat de la fonction ne peut pas être contrôlé par la fonction elle-même.

Pour éviter ce genre de comportement, vous pouvez écrire un incrément() qui prend des arguments et renvoie une valeur cohérente qui ne dépend que des arguments d'entrée:

>>>

>>> compteur = 0

>>> def incrément(var):
...     revenir var + 1
...

>>> incrément(compteur)
1

>>> compteur
0

>>> # Attribuer explicitement une nouvelle valeur au compteur
>>> compteur = incrément(compteur)
>>> compteur
1

Maintenant le résultat de l'appel incrément() dépend uniquement des arguments d'entrée plutôt que de la valeur initiale de compteur. Cela rend la fonction plus robuste et plus facile à tester.

De plus, lorsque vous devez mettre à jour compteur, vous pouvez le faire explicitement avec un appel à incrément(). De cette façon, vous aurez plus de contrôle sur ce qui se passe avec compteur tout au long de votre code.

En général, il est recommandé d’éviter les fonctions qui modifient les variables globales. Si possible, essayez d'écrire fonctions autonomes avec un explicite revenir instruction qui renvoie une valeur cohérente et significative.

En utilisant revenir Avec conditionnels

Les fonctions Python ne se limitent pas à avoir un seul revenir déclaration. Si une fonction donnée en a plus d'une revenir instruction, puis la première rencontrée déterminera la fin de l’exécution de la fonction ainsi que sa valeur de retour.

Une manière courante d'écrire des fonctions avec plusieurs revenir est d'utiliser des instructions conditionnelles qui vous permettent de fournir des revenir selon le résultat de l’évaluation de certaines conditions.

Supposons que vous ayez besoin de coder une fonction qui prend un nombre et renvoie sa valeur absolue. Si le nombre est supérieur à 0, alors vous retournerez le même numéro. Si le nombre est inférieur à 0, vous retournerez alors sa valeur opposée ou non négative.

Voici une implémentation possible pour cette fonction:

>>>

>>> def mes_abs(nombre):
...     si nombre > 0:
...         revenir nombre
...     elif nombre < 0:
...         revenir -nombre
...

>>> mes_abs(-15)
15

>>> mes_abs(15)
15

mes_abs () a deux explicites revenir déclarations, chacune enveloppée dans son propre si déclaration. Il a également un implicite revenir déclaration. Si nombre s'avère être 0, alors aucune condition n'est vraie, et la fonction se termine sans toucher aucun explicite revenir déclaration. Lorsque cela se produit, vous obtenez automatiquement Aucun.

Jetez un œil à l'appel suivant à mes_abs () en utilisant 0 comme argument:

>>>

>>> impression(mes_abs(0))
Aucun

Quand vous appelez mes_abs () en utilisant 0 comme argument, vous obtenez Aucun Par conséquent. C'est parce que le flux d'exécution arrive à la fin de la fonction sans atteindre aucun explicite revenir déclaration. Malheureusement, la valeur absolue de 0 est 0, ne pas Aucun.

Pour résoudre ce problème, vous pouvez ajouter un troisième revenir déclaration, soit dans une nouvelle elif clause ou dans un final autre clause:

>>>

>>> def mes_abs(nombre):
...     si nombre > 0:
...         revenir nombre
...     elif nombre < 0:
...         revenir -nombre
...     autre:
...         revenir 0
...

>>> mes_abs(0)
0

>>> mes_abs(-15)
15

>>> mes_abs(15)
15

Maintenant, mes_abs () vérifie toutes les conditions possibles, nombre> 0, nombre <0, et nombre == 0. Le but de cet exemple est de montrer que lorsque vous utilisez des instructions conditionnelles pour fournir plusieurs revenir instructions, vous devez vous assurer que chaque option possible a sa propre revenir déclaration. Sinon, votre fonction aura un bogue caché.

Enfin, vous pouvez implémenter mes_abs () d'une manière plus concise, efficace et pythonique en utilisant un seul si déclaration:

>>>

>>> def mes_abs(nombre):
...     si nombre < 0:
...         revenir -nombre
...     revenir nombre
...

>>> mes_abs(0)
0

>>> mes_abs(-15)
15

>>> mes_abs(15)
15

Dans ce cas, votre fonction atteint le premier revenir déclaration si nombre <0. Dans tous les autres cas, si nombre> 0 ou nombre == 0, ça frappe la seconde revenir déclaration. Avec cette nouvelle implémentation, votre fonction est bien meilleure. Il est plus lisible, concis et efficace.

Si vous utilisez si déclarations pour fournir plusieurs revenir déclarations, alors vous n’avez pas besoin autre clause pour couvrir la dernière condition. Ajoutez simplement un revenir instruction à la fin du bloc de code de la fonction et au premier niveau d'indentation.

Retour Vrai ou Faux

Un autre cas d'utilisation courant pour la combinaison de si et revenir est lorsque vous codez un prédicat ou une fonction à valeur booléenne. Ce type de fonction renvoie soit Vrai ou Faux selon une condition donnée.

Par exemple, disons que vous devez écrire une fonction qui prend deux entiers, une et b, et retourne Vrai si une est divisible par b. Sinon, la fonction doit retourner Faux. Voici une mise en œuvre possible:

>>>

>>> def is_divisible(une, b):
...     si ne pas une % b:
...         revenir Vrai
...     revenir Faux
...

>>> is_divisible(4, 2)
Vrai

>>> is_divisible(7, 4)
Faux

is_divisible () Retour Vrai si le reste de la division une par b est égal à 0. Sinon, il retourne Faux. Notez qu'en Python, un 0 la valeur est fausse, vous devez donc utiliser le ne pas opérateur pour nier la valeur de vérité de la condition.

Parfois, vous écrivez des fonctions de prédicat qui impliquent des opérateurs tels que les suivants:

Dans ces cas, vous pouvez directement utiliser une expression booléenne dans votre revenir déclaration. Ceci est possible car ces opérateurs renvoient soit Vrai ou Faux. Suite à cette idée, voici une nouvelle implémentation de is_divisible ():

>>>

>>> def is_divisible(une, b):
...     revenir ne pas une % b
...

>>> is_divisible(4, 2)
Vrai

>>> is_divisible(7, 4)
Faux

Si une est divisible par b, puis un B Retour 0, ce qui est faux en Python. Alors, pour revenir Vrai, vous devez utiliser le ne pas opérateur.

D'un autre côté, si vous essayez d'utiliser des conditions qui impliquent des opérateurs booléens comme ou et et comme vous l'avez vu auparavant, vos fonctions de prédicat ne fonctionneront pas correctement. C'est parce que ces opérateurs se comportent différemment. Ils renvoient l'un des opérandes de la condition plutôt que Vrai ou Faux:

>>>

>>> 0 et 1
0
>>> 1 et 2
2

>>> 1 ou 2
1
>>> 0 ou 1
1

En général, et renvoie le premier faux opérande ou le dernier opérande. D'autre part, ou renvoie le premier vrai opérande ou le dernier opérande. Par conséquent, pour écrire un prédicat impliquant l'un de ces opérateurs, vous devrez utiliser un si instruction ou un appel à la fonction intégrée booléen ().

Supposons que vous souhaitiez écrire une fonction de prédicat qui prend deux valeurs et renvoie Vrai si les deux sont vrais et Faux autrement. Voici votre première approche de cette fonction:

>>>

>>> def both_true(une, b):
...     revenir une et b
...
>>> both_true(1, 2)
2

Puisque et renvoie des opérandes au lieu de Vrai ou Faux, votre fonction ne fonctionne pas correctement. Il existe au moins trois possibilités pour résoudre ce problème:

  1. Un explicite si déclaration
  2. Une expression conditionnelle (opérateur ternaire)
  3. La fonction Python intégrée booléen ()

Si vous utilisez la première approche, vous pouvez écrire both_true () comme suit:

>>>

>>> def both_true(une, b):
...     si une et b:
...         revenir Vrai
...     revenir Faux
...

>>> both_true(1, 2)
Vrai

>>> both_true(1, 0)
Faux

le si relevé vérifie si une et b sont tous les deux véridiques. Si oui, alors both_true () Retour Vrai. Sinon, il retourne Faux.

Si, en revanche, vous utilisez une expression conditionnelle Python ou un opérateur ternaire, vous pouvez écrire votre fonction de prédicat comme suit:

>>>

>>> def both_true(une, b):
...     revenir Vrai si une et b autre Faux
...
>>> both_true(1, 2)
Vrai

>>> both_true(1, 0)
Faux

Ici, vous utilisez une expression conditionnelle pour fournir une valeur de retour pour both_true (). L'expression conditionnelle est évaluée à Vrai si les deux une et b sont véridiques. Sinon, le résultat final est Faux.

Enfin, si vous utilisez booléen (), alors vous pouvez coder both_true () comme suit:

>>>

>>> def both_true(une, b):
...     revenir booléen(une et b)
...

>>> both_true(1, 2)
Vrai

>>> both_true(1, 0)
Faux

booléen () Retour Vrai si une et b sont vrais et Faux autrement. C'est à vous de décider quelle approche utiliser pour résoudre ce problème. Cependant, la deuxième solution semble plus lisible. Qu'est-ce que tu penses?

Boucles de court-circuit

UNE revenir instruction à l'intérieur d'une boucle effectue une sorte de court-circuit. Il interrompt l'exécution de la boucle et fait revenir la fonction immédiatement. Pour mieux comprendre ce comportement, vous pouvez écrire une fonction qui émule tout(). Cette fonction intégrée prend un itérable et retourne Vrai si au moins un de ses éléments est véridique.

Pour émuler tout(), vous pouvez coder une fonction comme celle-ci:

>>>

>>> def my_any(itérable):
...     pour article dans itérable:
...         si article:
...             # Court-circuit
...             revenir Vrai
...     revenir Faux

>>> my_any([[[[0, 0, 1, 0, 0])
Vrai

>>> my_any([[[[0, 0, 0, 0, 0])
Faux

Si seulement article dans itérable est vrai, alors le flux d'exécution entre dans le si bloquer. le revenir L'instruction rompt la boucle et retourne immédiatement avec une valeur de retour de Vrai. Si aucune valeur dans itérable est vrai, alors my_any () Retour Faux.

Cette fonction implémente un évaluation des courts-circuits. Par exemple, supposons que vous transmettiez un itérable contenant un million d'éléments. Si le premier élément de cet itérable s'avère vrai, la boucle ne s'exécute qu'une seule fois au lieu d'un million de fois. Cela peut vous faire gagner beaucoup de temps lors de l'exécution de votre code.

Il est important de noter que pour utiliser un revenir dans une boucle, vous devez envelopper l'instruction dans un si déclaration. Sinon, la boucle sera toujours interrompue lors de sa première itération.

Reconnaître le code mort

Dès qu'une fonction atteint un revenir instruction, il se termine sans exécuter de code ultérieur. Par conséquent, le code qui apparaît après la fonction revenir la déclaration est communément appelée code mort. L'interpréteur Python ignore totalement le code mort lors de l'exécution de vos fonctions. Donc, avoir ce genre de code dans une fonction est inutile et déroutant.

Considérez la fonction suivante, qui ajoute du code après sa revenir déclaration:

>>>

>>> def dead_code():
...     revenir 42
...     # Code mort
...     impression("Bonjour le monde")
...

>>> dead_code()
42

La déclaration print ("Hello, World") dans cet exemple ne s’exécutera jamais car cette instruction apparaît après la fonction revenir déclaration. Identifier le code mort et le supprimer est une bonne pratique que vous pouvez appliquer pour écrire de meilleures fonctions.

Il convient de noter que si vous utilisez des instructions conditionnelles pour fournir plusieurs revenir instructions, alors vous pouvez avoir du code après un revenir déclaration qui ne sera pas morte tant qu’elle est en dehors de si déclaration:

>>>

>>> def no_dead_code(état):
...     si état:
...         revenir 42
...     impression("Bonjour le monde")
...

>>> no_dead_code(Vrai)
42
>>> no_dead_code(Faux)
Bonjour le monde

Même si l'appel à impression() est après un revenir statement, it’s not dead code. When condition is evaluated to False, le print() call is run and you get Hello, World printed to your screen.

Returning Multiple Named-Objects

When you’re writing a function that returns multiple values in a single revenir statement, you can consider using a collections.namedtuple object to make your functions more readable. namedtuple is a collection class that returns a subclass of tuple that has fields or attributes. You can access those attributes using dot notation or an indexing operation.

The initializer of namedtuple takes several arguments. However, to start using namedtuple in your code, you just need to know about the first two:

  1. typename holds the name of the tuple-like class that you’re creating. It needs to be a string.
  2. field_names holds the names of the fields or attributes of the tuple-like class. It can be a sequence of strings such as ["x", "y"] or a single string with each name separated by whitespace or commas, such as "x y" ou "x, y".

Using a namedtuple when you need to return multiple values can make your functions significantly more readable without too much effort. Consider the following update of describe() using a namedtuple as a return value:

importer statistics comme st
de collections importer namedtuple

def describe(sample):
    Desc = namedtuple("Desc", [[[["mean", "median", "mode"])
    revenir Desc(
        st.signifier(sample),
        st.median(sample),
        st.mode(sample),
    )

Inside describe(), you create a namedtuple appelé Desc. This object can have named attributes that you can access by using dot notation or by using an indexing operation. In this example, those attributes are "mean", "median", et "mode".

You can create a Desc object and use it as a return value. To do that, you need to instantiate Desc like you’d do with any Python class. Note that you need to supply a concrete value for each named attribute, just like you did in your revenir statement.

Voici comment describe() works now:

>>>

>>> sample = [[[[dix, 2, 4, 7, 9, 3, 9, 8, 6, 7]
>>> stat_desc = describe(sample)

>>> stat_desc
Desc(mean=5.7, median=6.0, mode=6)

>>> # Get the mean by its attribute name
>>> stat_desc.signifier
5,7

>>> # Get the median by its index
>>> stat_desc[[[[1]
6.0

>>> # Unpack the values into three variables
>>> signifier, median, mode = describe(sample)

>>> signifier
5,7

>>> mode
6

When you call describe() with a sample of numeric data, you get a namedtuple object containing the mean, median, and mode of the sample. Note that you can access each element of the tuple by using either dot notation or an indexing operation.

Finally, you can also use an iterable unpacking operation to store each value in its own independent variable.

Returning Functions: Closures

In Python, functions are first-class objects. A first-class object is an object that can be assigned to a variable, passed as an argument to a function, or used as a return value in a function. So, you can use a function object as a return value in any revenir statement.

A function that takes a function as an argument, returns a function as a result, or both is a higher-order function. A closure factory function is a common example of a higher-order function in Python. This kind of function takes some arguments and returns an inner function. The inner function is commonly known as a closure.

A closure carries information about its enclosing execution scope. This provides a way to retain state information between function calls. Closure factory functions are useful when you need to write code based on the concept of lazy or delayed evaluation.

Suppose you need to write a helper function that takes a number and returns the result of multiplying that number by a given factor. You can code that function as follows:

def by_factor(factor, number):
    revenir factor * number

by_factor() takes factor et number as arguments and returns their product. Since factor rarely changes in your application, you find it annoying to supply the same factor in every function call. So, you need a way to retain the state or value of factor between calls to by_factor() and change it only when needed. To retain the current value of factor between calls, you can use a closure.

The following implementation of by_factor() uses a closure to retain the value of factor between calls:

>>>

>>> def by_factor(factor):
...     def multiply(number):
...         revenir factor * number
...     revenir multiply
...

>>> double = by_factor(2)
>>> double(3)
6
>>> double(4)
8

>>> triple = by_factor(3)
>>> triple(3)
9
>>> triple(4)
12

Inside by_factor(), you define an inner function called multiply() and return it without calling it. The function object you return is a closure that retains information about the state of factor. In other words, it remembers the value of factor between calls. That’s why double remembers that factor was equal to 2 et triple remembers that factor was equal to 3.

Note that you can freely reuse double et triple because they don’t forget their respective state information.

You can also use a lambda function to create closures. Sometimes the use of a lambda function can make your closure factory more concise. Here’s an alternative implementation of by_factor() using a lambda function:

>>>

>>> def by_factor(factor):
...     revenir lambda number: factor * number
...

>>> double = by_factor(2)
>>> double(3)
6
>>> double(4)
8

This implementation works just like the original example. In this case, the use of a lambda function provides a quick and concise way to code by_factor().

Taking and Returning Functions: Decorators

Another way of using the revenir statement for returning function objects is to write decorator functions. UNE decorator function takes a function object as an argument and returns a function object. The decorator processes the decorated function in some way and returns it or replaces it with another function or callable object.

Decorators are useful when you need to add extra logic to existing functions without modifying them. For example, you can code a decorator to log function calls, validate the arguments to a function, measure the execution time of a given function, and so on.

The following example shows a decorator function that you can use to get an idea of the execution time of a given Python function:

>>>

>>> importer temps

>>> def my_timer(func):
...     def _timer(*args, **kwargs):
...         start = temps.temps()
...         result = func(*args, **kwargs)
...         fin = temps.temps()
...         impression(F"Execution time: fin - start")
...         revenir result
...     revenir _timer
...

>>> @my_timer
... def delayed_mean(sample):
...     temps.dormir(1)
...     revenir sum(sample) / len(sample)
...

>>> delayed_mean([[[[dix, 2, 4, 7, 9, 3, 9, 8, 6, 7])
Execution time: 1.0011096000671387
6.5

The syntax @my_timer above the header of delayed_mean() is equivalent to the expression delayed_mean = my_timer(delayed_mean). In this case, you can say that my_timer() is decorating delayed_mean().

Python runs decorator functions as soon as you import or run a module or a script. So, when you call delayed_mean(), you’re really calling the return value of my_timer(), which is the function object _timer. The call to the decorated delayed_mean() will return the mean of the sample and will also measure the execution time of the original delayed_mean().

In this case, you use time() to measure the execution time inside the decorator. time() lives in a module called temps that provides a set of time-related functions. time() returns the time in seconds since the epoch as a floating-point number. The difference between the time before and after the call to delayed_mean() will give you an idea of the function’s execution time.

Other common examples of decorators in Python are classmethod(), staticmethod(), et property(). If you want to dive deeper into Python decorators, then take a look at Primer on Python Decorators. You can also check out Python Decorators 101.

Returning User-Defined Objects: The Factory Pattern

The Python revenir statement can also return user-defined objects. In other words, you can use your own custom objects as a return value in a function. A common use case for this capability is the factory pattern.

The factory pattern defines an interface for creating objects on the fly in response to conditions that you can’t predict when you’re writing a program. You can implement a factory of user-defined objects using a function that takes some initialization arguments and returns different objects according to the concrete input.

Say you’re writing a painting application. You need to create different shapes on the fly in response to your user’s choices. Your program will have squares, circles, rectangles, and so on. To create those shapes on the fly, you first need to create the shape classes that you’re going to use:

class Circle:
    def __init__(self, radius):
        self.radius = radius
    # Class implementation...

class Carré:
    def __init__(self, side):
        self.side = side
    # Class implementation...

Once you have a class for each shape, you can write a function that takes the name of the shape as a string and an optional list of arguments (*args) and keyword arguments (**kwargs) to create and initialize shapes on the fly:

def shape_factory(shape_name, *args, **kwargs):
    shapes = "circle": Circle, "square": Carré
    revenir shapes[[[[shape_name](*args, **kwargs)

This function creates an instance of the concrete shape and returns it to the caller. Now you can use shape_factory() to create objects of different shapes in response to the needs of your users:

>>>

>>> circle = shape_factory("circle", radius=20)
>>> type(circle)

>>> circle.radius
20

>>> square = shape_factory("square", side=dix)
>>> type(square)

square.side
dix

If you call shape_factory() with the name of the required shape as a string, then you get a new instance of the shape that matches the shape_name you’ve just passed to the factory.

Using revenir dans try...finally Blocks

When you use a revenir statement inside a essayer statement with a finally clause, that finally clause is always executed before the revenir statement. This ensures that the code in the finally clause will always run. Check out the following example:

>>>

>>> def func(value):
...     essayer:
...         revenir float(value)
...     except ValueError:
...         revenir str(value)
...     finally:
...         impression("Run this before returning")
...

>>> func(9)
Run this before returning
9,0

>>> func("one")
Run this before returning
'one'

When you call func(), you get value converted to a floating-point number or a string object. Before doing that, your function runs the finally clause and prints a message to your screen. Whatever code you add to the finally clause will be executed before the function runs its revenir statement.

Using revenir in Generator Functions

A Python function with a rendement statement in its body is a generator function. When you call a generator function, it returns a generator iterator. So, you can say that a generator function is a generator factory.

Vous pouvez utiliser un revenir statement inside a generator function to indicate that the generator is done. le revenir statement will make the generator raise a StopIteration. The return value will be passed as an argument to the initializer of StopIteration and will be assigned to its .value attribute.

Here’s a generator that yields 1 et 2 on demand and then returns 3:

>>>

>>> def gen():
...     rendement 1
...     rendement 2
...     revenir 3
...

>>> g = gen()
>>> g


>>> next(g)
1
>>> next(g)
2

>>> next(g)
Traceback (most recent call last):
  File "", line 1, in 
    next(g)
StopIteration: 3

gen() returns a generator object that yields 1 et 2 on demand. To retrieve each number form the generator object, you can use next(), which is a built-in function that retrieves the next item from a Python generator.

The first two calls to next() retrieve 1 et 2, respectively. In the third call, the generator is exhausted, and you get a StopIteration. Note that the return value of the generator function (3) becomes the .value attribute of the StopIteration object.

Conclusion

The Python revenir statement allows you to send any Python object from your custom functions back to the caller code. This statement is a fundamental part of any Python function or method. If you master how to use it, then you’ll be ready to code robust functions.

In this tutorial, you’ve learned how to:

  • Effectively use the Python revenir déclaration in your functions
  • Revenir single ou multiple values from your functions to the caller code
  • Apply best practices when using the revenir déclaration

Additionally, you’ve learned some more advanced use cases for the revenir statement, like how to code a closure factory function and a decorator function. With this knowledge, you’ll be able to write more Pythonic, robust, and maintainable functions in Python.