Règles de portée dans les fonctions Python


Python est un langage à portée statique, bien qu'il soit lui-même un langage dynamique. En d’autres termes, la portée d’une variable en Python est déterminée par sa position dans le code source, ce qui est quelque peu similaire à C, mais la différence de portée entre Python et C reste très évidente.


Ensuite, nous parlerons des règles de portée de Python, et nous expliquerons également les différences entre Python et C en termes de portée.

Dans Python 2.0 et les versions précédentes, Python ne prenait en charge que 3 types de portée, à savoir la portée locale, la portée globale et la portée intégrée ; dans Python 2.2, Python a officiellement introduit une nouvelle portée --- Portée imbriquée dans Python 2.1, La portée imbriquée peut être activée en option ; l'introduction de la portée imbriquée implémente essentiellement la prise en charge des fermetures en Python. Il existe de nombreuses explications sur la connaissance des fermetures sur Internet, qui ne seront pas discutées en détail ici. En conséquence, l'ordre de recherche des variables passe du LGB précédent au LEGB (L : local, E : englobant, G : global, B : intégré).


En Python, aucun bloc de code ne peut introduire une nouvelle portée, ce qui est très différent de C :


#include<stdio.h>int main() {    if(2 > 0) {        int i = 0;
    }
    printf("i = %d", i);    return 0;
}

Dans ce code, le if sub La phrase introduit une portée locale. La variable i existe dans cette portée locale mais n'est pas visible par le monde extérieur. Par conséquent, la référence ultérieure à la variable i dans la fonction printf provoquera une erreur de compilation.

Cependant, ce n'est pas le cas en Python :

if True:
    i = 0print i

Dans ce code, la clause if n'introduit pas de portée locale, la variable i est toujours dans la portée globale, donc la variable i est pour le prochain La déclaration d'impression est visible.

En fait, en Python, seuls les modules, classes et fonctions introduiront de nouvelles portées, et les autres blocs de code n'introduiront pas de nouvelles portées.

En Python, vous n'êtes pas obligé de pré-déclarer une variable avant de l'utiliser, mais avant de l'utiliser réellement, elle doit avoir été liée à un objet ; la liaison de nom introduira une nouvelle variable dans la portée actuelle tout en protégeant le monde extérieur. Une variable avec le même nom dans la portée de la couche, quel que soit l'endroit où la liaison de nom se produit dans la portée actuelle.

def f():    print i
f()


Le résultat de l'exécution affichera : NameError : le nom global 'i' n'est pas défini. Python recherche d'abord la variable i dans la portée locale de la fonction f, et la recherche échoue. Ensuite, il recherche la variable i dans la portée globale et la portée intégrée, mais échoue toujours et lève finalement une exception NameError.

i = 0def f():
    i = 8    print i
f()print i


Les résultats en cours d'exécution montrent : 8 et 0. i = 8 est une opération de liaison de nom. Elle introduit une nouvelle variable i dans la portée locale de la fonction f et bloque la variable globale i. Par conséquent, l'instruction print à l'intérieur de f voit la variable locale i et l'instruction print à l'extérieur de f voit la variable locale i. variable locale i. Ce que l'instruction voit est la variable globale i.

i = 0def f():    print i
    i = 0
f()


Le résultat en cours d'exécution montre : UnboundLocalError : variable locale 'i' référencée avant l'affectation. Dans cet exemple, la variable i dans la fonction f est une variable locale, mais lorsque l'instruction print l'utilise, elle n'a été liée à aucun objet, donc une exception est levée.

print i
i = 0


Qu'il soit exécuté de manière interactive ou sous forme de fichier script, le résultat affiche : NameError : le nom 'i' n'est pas défini. Le résultat ici est différent de l’exemple précédent car il se situe dans la portée de niveau supérieur (portée du module). Pour le code du module, le code ne subit aucun prétraitement avant l'exécution, mais pour le corps de la fonction, le code a déjà subi un prétraitement avant l'exécution, donc peu importe où la liaison de nom se produit dans la portée, il peut le sentir. Bien que Python soit un langage à portée statique, les recherches de noms se produisent de manière dynamique, de sorte que les problèmes de noms ne sont découverts qu'au moment de l'exécution.


En Python, la liaison de nom introduit une nouvelle variable dans la portée à laquelle elle appartient et la lie à un objet. La liaison de nom se produit dans les situations suivantes :


  1. Déclaration de paramètre : La déclaration de paramètre introduit de nouvelles variables dans la portée locale de la fonction
  2. Opération d'affectation : À a L'affectation initiale d'un ; La variable introduira une nouvelle variable dans la portée actuelle, et les opérations d'affectation ultérieures relieront la variable.
  3. Définition de classe et de fonction : La définition de classe et de fonction introduira le nom de la classe et le nom de la fonction en tant que variables La portée actuelle, la classe body et function body formeront une autre portée ; variables (variables de boucle) dans la portée actuelle ;
  4. instruction except : l'instruction sauf introduit de nouvelles variables (objets d'exception) dans la portée actuelle.
  5. En Python, la portée introduite par la définition de classe est invisible pour la fonction membre. C'est très différent de C++ ou Java, donc en Python, la fonction membre veut référencer la définition du corps de classe. Une variable. doit être référencé par le nom de soi ou de la classe.
  6. L'ajout de portées imbriquées entraînera l'échec de la compilation de certains codes ou l'obtention de résultats d'exécution différents. Ici, l'interpréteur Python vous aidera à identifier ces endroits qui peuvent causer des problèmes et donner des avertissements.
La fonction locals renvoie toutes les variables locales, mais ne renverra pas les variables dans les portées imbriquées. En fait, aucune fonction ne renverra les variables dans les portées imbriquées.