Valeurs de Retour et Portée des Fonctions en Python

PythonBeginner
Pratiquer maintenant

Introduction

Dans ce laboratoire, vous approfondirez votre compréhension des fonctions en Python en explorant leurs valeurs de retour et le concept de portée des variables (scope). Vous commencerez par examiner les fonctions qui ne retournent pas explicitement de valeur, en observant comment elles exécutent des actions sans produire de résultat utilisable ailleurs.

Par la suite, vous apprendrez à ajouter des valeurs de retour aux fonctions, leur permettant de produire une sortie qui peut être capturée et utilisée dans vos programmes. Le laboratoire vous guidera ensuite pour différencier les variables locales et globales, comprendre leurs portées respectives et comment elles affectent l'accessibilité des variables à l'intérieur et à l'extérieur des fonctions. Vous apprendrez également à modifier les variables globales depuis l'intérieur des fonctions en utilisant le mot-clé global et explorerez le concept des variables nonlocal dans les fonctions imbriquées.

Explorer les Fonctions Sans Valeurs de Retour

Dans cette étape, nous allons explorer les fonctions qui ne possèdent pas d'instruction return explicite. Ces fonctions exécutent une action, comme imprimer dans la console, mais ne renvoient aucune valeur à la partie du code qui les a appelées.

Tout d'abord, localisez le fichier no_return_function.py dans l'explorateur de fichiers situé sur le côté gauche du WebIDE. Double-cliquez dessus pour l'ouvrir dans l'éditeur.

Ajoutez le code suivant au fichier no_return_function.py :

def greet():
    print("Hello, welcome to the world of functions!")

## Call the function
greet()

Pour exécuter ce script, ouvrez le terminal intégré en cliquant sur Terminal > New Terminal dans le menu supérieur. Ensuite, exécutez la commande suivante :

python ~/project/no_return_function.py

Vous verrez la sortie de la fonction imprimée dans la console :

Hello, welcome to the world of functions!

La fonction greet() exécute l'instruction print(), mais elle ne produit pas de valeur qui puisse être stockée dans une variable. Pour voir ce qui se passe lorsque vous tentez de capturer le résultat, modifiez le fichier no_return_function.py. Remplacez le contenu existant par le code suivant :

def greet():
    print("Hello, welcome to the world of functions!")

## Call the function and assign its result to a variable
result = greet()

## Print the value of the result
print(f"The result of calling greet() is: {result}")

Enregistrez le fichier et exécutez-le à nouveau depuis le terminal :

python ~/project/no_return_function.py

La sortie sera maintenant :

Hello, welcome to the world of functions!
The result of calling greet() is: None

Comme vous pouvez le constater, la valeur de la variable result est None. En Python, toute fonction qui ne possède pas d'instruction return explicite retourne automatiquement None. None est une valeur spéciale qui représente l'absence de valeur. Cela confirme que de telles fonctions sont utilisées pour leurs effets secondaires (comme l'impression) plutôt que pour la production de données.

Ajouter des Valeurs de Retour aux Fonctions

Contrairement à l'étape précédente, la plupart des fonctions sont conçues pour calculer une valeur et la retourner à l'appelant. Ceci est réalisé à l'aide du mot-clé return. Une instruction return sort immédiatement de la fonction et renvoie une valeur spécifiée.

Ouvrez le fichier return_function.py depuis l'explorateur de fichiers dans votre WebIDE.

Ajoutez le code suivant pour définir une fonction qui additionne deux nombres et retourne leur somme :

def add_numbers(a, b):
    """This function adds two numbers and returns the sum."""
    sum_result = a + b
    return sum_result

## Call the function and store the returned value
total = add_numbers(5, 3)

## Print the returned value
print(f"The sum is: {total}")

## Use the returned value in another operation
another_total = add_numbers(10, 20) * 2
print(f"Another calculated value: {another_total}")

Enregistrez le fichier et exécutez le script depuis le terminal :

python ~/project/return_function.py

Vous devriez voir la sortie suivante, montrant que les valeurs retournées ont été capturées et utilisées avec succès :

The sum is: 8
Another calculated value: 60

Une fonction peut retourner n'importe quel objet Python, y compris des nombres, des chaînes de caractères (strings), des listes, et même des tuples. Retourner un tuple est une manière courante de retourner plusieurs valeurs en une seule fois.

Ajoutez le code suivant à la fin de votre fichier return_function.py pour voir cela en action :

def get_user_info():
    """This function returns user information as a tuple."""
    name = "labex"
    age = 25
    city = "Virtual City"
    return name, age, city

## Call the function and unpack the returned tuple into separate variables
user_name, user_age, user_city = get_user_info()

## Print the unpacked values
print(f"Name: {user_name}, Age: {user_age}, City: {user_city}")

Enregistrez le fichier et exécutez-le à nouveau :

python ~/project/return_function.py

La sortie complète sera maintenant :

The sum is: 8
Another calculated value: 60
Name: labex, Age: 25, City: Virtual City

Ici, get_user_info() retourne trois valeurs empaquetées dans un tuple. Le code appelant dépaquette ensuite ce tuple dans trois variables distinctes, ce qui facilite le travail avec plusieurs valeurs de retour.

Différencier les Variables Locales et Globales

Comprendre la portée (scope) des variables est essentiel pour écrire du code sans bug. La portée détermine où, dans votre programme, une variable peut être accédée.

  • Portée Globale (Global Scope) : Les variables définies en dehors de toute fonction sont globales. Elles peuvent être accédées depuis n'importe où dans votre script.
  • Portée Locale (Local Scope) : Les variables définies à l'intérieur d'une fonction sont locales. Elles ne peuvent être accédées qu'à l'intérieur de cette fonction.

Explorons ce concept. Ouvrez le fichier variable_scope.py dans le WebIDE.

Ajoutez le code suivant au fichier :

## Global variable
global_variable = "I am a global variable"

def my_function():
    ## Local variable
    local_variable = "I am a local variable"
    print(f"Inside the function:")
    print(f"  Accessing global_variable: {global_variable}")
    print(f"  Accessing local_variable: {local_variable}")

## Call the function
my_function()

## Try to access variables outside the function
print(f"\nOutside the function:")
print(f"  Accessing global_variable: {global_variable}")

## Attempting to access local_variable here would cause a NameError
## print(f"  Accessing local_variable: {local_variable}")

Enregistrez le fichier et exécutez-le depuis le terminal :

python ~/project/variable_scope.py

La sortie démontre l'accessibilité de chaque variable :

Inside the function:
  Accessing global_variable: I am a global variable
  Accessing local_variable: I am a local variable

Outside the function:
  Accessing global_variable: I am a global variable

La variable globale est accessible partout, mais la variable locale est confinée à sa fonction. Si vous décommentez la dernière ligne, le script échouera avec une NameError.

Maintenant, que se passe-t-il si une variable locale porte le même nom qu'une variable globale ? La variable locale "masque" (shadows) la variable globale, ce qui signifie qu'à l'intérieur de la fonction, le nom fera référence à la variable locale.

Ajoutez le code suivant à la fin de votre fichier variable_scope.py pour observer cet effet de masquage :

## Global variable
my_variable = "I am the global version"

def another_function():
    ## This local variable shadows the global one
    my_variable = "I am the local version"
    print(f"\nInside another_function(): {my_variable}")

## Call the function
another_function()

## The global variable remains unchanged
print(f"Outside another_function(): {my_variable}")

Enregistrez et exécutez à nouveau le script :

python ~/project/variable_scope.py

La sortie complète sera maintenant :

Inside the function:
  Accessing global_variable: I am a global variable
  Accessing local_variable: I am a local variable

Outside the function:
  Accessing global_variable: I am a global variable

Inside another_function(): I am the local version
Outside another_function(): I am the global version

À l'intérieur de another_function(), my_variable fait référence à la version locale. À l'extérieur, elle fait référence à la version globale. L'affectation à l'intérieur de la fonction n'a pas affecté la variable globale.

Modifier les Variables Globales en Utilisant le Mot-Clé global

Par défaut, vous ne pouvez pas modifier la valeur d'une variable globale depuis l'intérieur d'une fonction. Une instruction d'affectation à l'intérieur d'une fonction crée une nouvelle variable locale. Pour modifier explicitement une variable globale, vous devez utiliser le mot-clé global.

Ouvrez le fichier modify_global.py dans le WebIDE.

Ajoutez le code suivant, qui définit un compteur global et une fonction pour l'incrémenter :

## Global variable
counter = 0

def increment_counter():
    ## Declare that we intend to modify the global counter
    global counter
    counter += 1
    print(f"Inside function: counter is {counter}")

## Print the initial value
print(f"Before calling function: counter is {counter}")

## Call the function to modify the global variable
increment_counter()

## Print the value after the function call
print(f"After calling function: counter is {counter}")

Enregistrez le fichier et exécutez-le depuis le terminal :

python ~/project/modify_global.py

La sortie montre que la variable globale a été modifiée avec succès :

Before calling function: counter is 0
Inside function: counter is 1
After calling function: counter is 1

L'instruction global counter indique à Python que toute opération sur counter à l'intérieur de cette fonction doit affecter la variable globale, et non une nouvelle variable locale.

Pour contraster, ajoutons une autre fonction qui n'utilise pas le mot-clé global. Ajoutez le code suivant à la fin de modify_global.py :

def increment_counter_local():
    ## This assignment creates a new local variable named 'counter'
    counter = 100
    print(f"\nInside function (local): counter is {counter}")

## Print the global counter's value before the test
print(f"Before calling function (local test): counter is {counter}")

## Call the function
increment_counter_local()

## The global counter's value is unaffected
print(f"After calling function (local test): counter is {counter}")

Enregistrez et exécutez à nouveau le script :

python ~/project/modify_global.py

La sortie complète démontre clairement la différence :

Before calling function: counter is 0
Inside function: counter is 1
After calling function: counter is 1
Before calling function (local test): counter is 1
Inside function (local): counter is 100
After calling function (local test): counter is 1

Dans le deuxième test, l'affectation counter = 100 n'a affecté qu'une variable locale à l'intérieur de increment_counter_local(). Le counter global a conservé sa valeur de 1.

Comprendre les Variables nonlocal dans les Fonctions Imbriquées

Les règles de portée (scope) de Python s'appliquent également aux fonctions imbriquées (une fonction définie à l'intérieur d'une autre fonction). Une variable qui n'est pas locale à la fonction interne mais qui est locale à la fonction externe est appelée une variable "nonlocale".

Pour modifier une telle variable depuis la fonction interne, vous devez utiliser le mot-clé nonlocal. C'est similaire au fonctionnement de global, mais cela s'applique aux portées imbriquées au lieu de la portée globale.

Ouvrez le fichier nonlocal_variable.py dans le WebIDE.

Ajoutez le code suivant pour démontrer l'utilisation de nonlocal :

def outer_function():
    outer_variable = "I am in the outer function"

    def inner_function():
        ## Declare that we are modifying the variable from the enclosing scope
        nonlocal outer_variable
        outer_variable = "I have been modified by the inner function"
        print(f"Inside inner_function(): {outer_variable}")

    print(f"Before calling inner_function(): {outer_variable}")
    inner_function()
    print(f"After calling inner_function(): {outer_variable}")

## Call the outer function
outer_function()

Enregistrez le fichier et exécutez-le depuis le terminal :

python ~/project/nonlocal_variable.py

La sortie montre que la fonction interne a modifié avec succès la variable de la fonction externe :

Before calling inner_function(): I am in the outer function
Inside inner_function(): I have been modified by the inner function
After calling inner_function(): I have been modified by the inner function

L'instruction nonlocal outer_variable permet à inner_function de réaffecter outer_variable depuis outer_function.

Voyons maintenant ce qui se passe sans le mot-clé nonlocal. Ajoutez le code suivant à la fin de nonlocal_variable.py :

def outer_function_local_test():
    outer_variable = "I am in the outer function (local test)"

    def inner_function_local_test():
        ## This assignment creates a new local variable
        outer_variable = "I am a local variable in inner_function"
        print(f"\nInside inner_function_local_test(): {outer_variable}")

    print(f"\nBefore calling inner_function_local_test(): {outer_variable}")
    inner_function_local_test()
    print(f"After calling inner_function_local_test(): {outer_variable}")

## Call the outer function for the local test
outer_function_local_test()

Enregistrez et exécutez à nouveau le script :

python ~/project/nonlocal_variable.py

La sortie complète met en évidence la différence :

Before calling inner_function(): I am in the outer function
Inside inner_function(): I have been modified by the inner function
After calling inner_function(): I have been modified by the inner function

Before calling inner_function_local_test(): I am in the outer function (local test)
Inside inner_function_local_test(): I am a local variable in inner_function
After calling inner_function_local_test(): I am in the outer function (local test)

Dans le deuxième exemple, l'affectation à l'intérieur de inner_function_local_test() a créé une nouvelle variable locale, laissant la outer_variable dans la portée englobante inchangée.

Résumé

Dans ce laboratoire, vous avez exploré plusieurs concepts clés liés aux fonctions Python. Vous avez commencé par apprendre que les fonctions sans instruction return explicite retournent implicitement None. Vous vous êtes ensuite exercé à utiliser le mot-clé return pour renvoyer des valeurs depuis une fonction, y compris le retour de plusieurs valeurs sous forme de tuple.

Vous avez également étudié la portée des variables (scope), en distinguant les variables locales (accessibles uniquement à l'intérieur d'une fonction) et les variables globales (accessibles dans tout le script). Vous avez appris comment fonctionne l'ombrage de variables (variable shadowing) et comment utiliser le mot-clé global pour modifier une variable globale depuis l'intérieur d'une fonction. Enfin, vous avez examiné les fonctions imbriquées et utilisé le mot-clé nonlocal pour modifier des variables dans une portée englobante, non globale.