Variables visibility and scope

Reading time10 min

En bref

Résumé de l’article

Dans cet article, nous discutons de la visibilité des variables.
Cela désigne la portée dans laquelle les variables existent et peuvent être utilisées.
En particulier, nous discutons de la différence entre les variables locales et globales.

Points clés

  • Les variables locales ne sont visibles que dans la portée de la fonction qui les utilise.

  • Les variables globales sont accessibles partout dans le programme.

  • Les variables globales doivent être évitées au profit des variables locales.

Contenu de l’article

Comme vu dans la session 1, une variable associe explicitement un nom à une valeur et occupe implicitement un espace en mémoire principale, dont la taille dépend du type de variable.
La valeur actuellement associée à la variable peut être accédée via le nom de la variable.

En raison des limitations de mémoire, toutes les variables n’existent pas tout au long de la vie d’un programme.
Un composant de l’interpréteur Python, appelé “ramasse-miettes” (garbage collector), supprime les variables qui ne peuvent plus être utilisées, libérant ainsi la mémoire qu’elles occupaient.

La visibilité d’une variable détermine sa durée de vie, et deux types de visibilité sont considérés en Python, à savoir les variables locales et globales.

1 — Variables locales vs globales

Les variables locales sont définies à l’intérieur d’une fonction et ne sont pas accessibles en dehors.

Exemple

Dans cet exemple, nous définissons deux variables a et b qui sont locales à la fonction example.
Elles n’existent que dans example et cessent d’exister une fois que la fonction/procédure a retourné/terminé.

# Define a function
def example (a):

    """
        This is an example function with two local variables.
        In:
            * a: An argument of the function.
        Out:
            * None.
    """

    # Define a local variable
    b = 2

    # Print variables
    print(a, b)



# Call it and try to access variables
example(1)
print(a, b)
/**
 * To run this code, you need to have Java installed on your computer, then:
 * - Create a file named `Main.java` in a directory of your choice.
 * - Copy this code in the file.
 * - Open a terminal in the directory where the file is located.
 * - Run the command `javac Main.java` to compile the code.
 * - Run the command `java -ea Main` to execute the compiled code.
 * Note: '-ea' is an option to enable assertions in Java.
 */
public class Main {

    /**
     * This is an example function with two local variables
     *
     * @param a An argument of the function.
     */
    public static void example(int a) {
        // Define a local variable
        int b = 2;
        // Print variables
        System.out.println(a + " " + b);
    }

    /**
     * This is the entry point of your program.
     * It contains the first codes that are going to be executed.
     *
     * @param args Command line arguments received.
     */
    public static void main(String[] args) {
        // Call it and try to access variables
        example(1);
        System.out.println(a + " " + b);
    }

}

Voici la sortie obtenue :

Sortie
1 2
Traceback (most recent call last):
  File "exaple.py", line 22, in <module>
    print(a, b)
NameError: name 'a' is not defined
Main.java:33: error: cannot find symbol
        System.out.println(a + " " + b);
                           ^
  symbol:   variable a
  location: class Main
Main.java:33: error: cannot find symbol
        System.out.println(a + " " + b);
                                     ^
  symbol:   variable b
  location: class Main
2 errors

Les variables globales sont définies en dehors de toutes les fonctions et accessibles partout dans le code.

Exemple

Déclarons une variable globale a, mais aussi une variable locale appelée a, et affichons-les :

# Define a global variable
a = 1



# Define a function
def example ():

    """
        Example function with a local variable, also named "a".
        In:
            * None.
        Out:
            * None.
    """

    # Define a local variable
    a = 2

    # Print a to see which one we use
    print(a)



# See what we got
print(a)
example()
print(a)
/**
 * To run this code, you need to have Java installed on your computer, then:
 * - Create a file named `Main.java` in a directory of your choice.
 * - Copy this code in the file.
 * - Open a terminal in the directory where the file is located.
 * - Run the command `javac Main.java` to compile the code.
 * - Run the command `java -ea Main` to execute the compiled code.
 * Note: '-ea' is an option to enable assertions in Java.
 */
public class Main {

    /**
     * Define a global variable (in Java, we use a class-level variable).
     */
    static int a = 1;

    /**
     * Example function with a local variable, also named "a".
     */
    public static void example() {
        // Define a local variable
        int a = 2;
        // Print a to see which one we use
        System.out.println(a);
    }

    /**
     * This is the entry point of your program.
     * It contains the first codes that are going to be executed.
     *
     * @param args Command line arguments received.
     */
    public static void main(String[] args) {
        // See what we got
        System.out.println(a);
        example();
        System.out.println(a);
    }

}

Voici la sortie obtenue :

Sortie
1
2
1
1
2
1

Notez que les variables locales “cachent” les variables globales portant le même nom.

2 — Les mots-clés global et nonlocal

Python offre deux mots-clés pour jouer avec la visibilité des variables.

Le mot-clé global est utilisé pour modifier une variable globale à l’intérieur d’une fonction.

Exemple

Adaptation du code ci-dessus, pour indiquer dans example que a est global.
Ici, le mot-clé global indique de ne pas redéfinir une nouvelle variable, mais de trouver une variable existante en mémoire globale.

# Define a global variable
a = 1



# Define a function
def example ():

    """
        Example function with access to global variable "a".
        In:
            * None.
        Out:
            * None.
    """

    # Indicate that a exists in the global scope
    global a

    # Update global variable
    a = 2

    # Print global variable
    print(a)



# See what we got
print(a)
example()
print(a)
/**
 * To run this code, you need to have Java installed on your computer, then:
 * - Create a file named `Main.java` in a directory of your choice.
 * - Copy this code in the file.
 * - Open a terminal in the directory where the file is located.
 * - Run the command `javac Main.java` to compile the code.
 * - Run the command `java -ea Main` to execute the compiled code.
 * Note: '-ea' is an option to enable assertions in Java.
 */
public class Main {

    /**
     * Define a global variable (in Java, we use a class-level variable).
     */
    static int a = 1;


    /**
     * Example function with access to global variable "a".
     */
    public static void example() {
        // Update global variable
        a = 2;
        // Print global variable
        System.out.println(a);
    }

    /**
     * This is the entry point of your program.
     * It contains the first codes that are going to be executed.
     *
     * @param args Command line arguments received.
     */
    public static void main(String[] args) {
        // See what we got
        System.out.println(a);
        example();
        System.out.println(a);
    }

}

Voici la sortie obtenue :

Sortie
1
2
2
1
2
2

Le mot-clé nonlocal est utilisé dans les fonctions imbriquées pour modifier une variable dans la portée englobante.
C’est une situation assez particulière, mais cela peut être utile lorsqu’on travaille avec des fonctions imbriquées.

Exemple

Adaptation du code ci-dessus avec une fonction imbriquée.
Notez que Java gère les portées différemment, il n’y a donc pas d’équivalent.

# Define a global variable
a = 1



# Define a function
def example ():

    """
        Example function with a nested function.
        Note that "inner" cannot be called from outside the body of function "example".
        In:
            * None.
        Out:
            * None.
    """
    
    # Local variable
    a = 2

    # Inner function
    def inner ():
        nonlocal a
        a = 3
    
    # Call inner function
    print(a)
    inner()
    print(a)



# See what we got
print(a)
example()
print(a)

Voici la sortie obtenue :

Sortie
1
2
3
1
1
2
3
1

Les variables locales et globales visibles sont stockées dans deux structures de données séparées (i.e., dictionnaires) qui peuvent être affichées en appelant respectivement les fonctions locals() et globals().

Important

En général, il est préférable d’éviter d’utiliser des variables globales, car elles peuvent être une source d’erreurs.
Par exemple, considérez la fonction suivante :

# Define a global variable
a = 1



# Define a function
def example (b):

    """
        Example function.
        In:
            * b: An argument of the function.
        Out:
            * The product of a and b.
    """

    # Indicate that a exists in the global scope
    global a

    # Update a
    a += 1

    # Return a computation that depends on a and b
    return a * b




# See what we got
res = example(2)
print(res)
res = example(2)
print(res)
/**
 * To run this code, you need to have Java installed on your computer, then:
 * - Create a file named `Main.java` in a directory of your choice.
 * - Copy this code in the file.
 * - Open a terminal in the directory where the file is located.
 * - Run the command `javac Main.java` to compile the code.
 * - Run the command `java -ea Main` to execute the compiled code.
 * Note: '-ea' is an option to enable assertions in Java.
 */
public class Main {

    /**
     * Define a global variable (in Java, we use a class-level variable).
     */
    static int a = 1;

    /**
     * Example function.
     *
     * @param b An argument of the function.
     */
    public static int example(int b) {
        // Update a
        a += 1;
        // Return a computation that depends on a and b
        return a * b;
    }

    /**
     * This is the entry point of your program.
     * It contains the first codes that are going to be executed.
     *
     * @param args Command line arguments received.
     */
    public static void main(String[] args) {
        // See what we got
        int res = example(2);
        System.out.println(res);
        res = example(2);
        System.out.println(res);
    }

}

L’appeler deux fois conduira à deux résultats différents (4, puis 6), ce qui n’est pas un comportement standard.

Pour aller plus loin

On dirait que cette section est vide !

Y a-t-il quelque chose que vous auriez aimé voir ici ?
Faites-le nous savoir sur le serveur Discord !
Peut-être pouvons-nous l’ajouter rapidement.
Sinon, cela nous aidera à améliorer le cours pour l’année prochaine !

Pour aller au-delà

  • Java Modifiers

    Certains langages, comme Java, fournissent des stratégies supplémentaires pour déterminer les niveaux d’accès aux variables et autres composants.