Il n'y avait pas de réponse approfondie concernant le temps Python3, donc j'ai fait une réponse ici. La plupart de ce qui est décrit ici est détaillé dans le document 4.2.2 Résolution des noms de la documentation de Python 3.
Comme indiqué dans d'autres réponses, il existe 4 champs d'application de base, les LEGB, pour Local, Enclosing, Global et Builtin. En plus de celles-ci, il y a une portée spéciale, le corps de classe qui ne comporte pas de portée englobante pour les méthodes définies dans la classe ; toute affectation dans le corps de la classe fait que la variable est désormais liée dans le corps de la classe.
Surtout, pas de l'énoncé du bloc, en plus def
y class
créer une variable de portée. Dans Python 2, une compréhension de liste ne crée pas de portée de variable, cependant dans Python 3, la variable de boucle dans les compréhensions de liste est créée dans une nouvelle portée.
Démontrer les particularités du corps de la classe
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Ainsi, contrairement à ce qui se passe dans le corps de la fonction, vous pouvez réassigner la variable au même nom dans le corps de la classe, pour obtenir une variable de classe avec le même nom ; les recherches ultérieures sur ce nom résolvent vers la variable de classe.
L'une des plus grandes surprises pour de nombreux nouveaux venus dans Python est qu'un fichier de type for
ne crée pas de portée de variable. En Python 2, les compréhensions de listes ne créent pas non plus de portée (alors que les générateurs et les compréhensions de dicts le font !) Au lieu de cela, ils font fuir la valeur dans la fonction ou la portée globale :
>>> [ i for i in range(5) ]
>>> i
4
Les compréhensions peuvent être utilisées comme un moyen astucieux (ou horrible si vous voulez) de rendre les variables modifiables dans les expressions lambda en Python 2 - une expression lambda crée une portée de variable, comme l'expression def
mais dans les lambdas, aucune déclaration n'est autorisée. L'assignation étant une instruction en Python, aucune assignation de variable n'est autorisée dans lambda, mais une compréhension de liste est une expression...
Ce comportement a été corrigé dans Python 3 - les expressions de compréhension ou les générateurs ne fuient plus les variables.
Le global signifie en réalité la portée du module ; le module python principal est le module __main__
; tous les modules importés sont accessibles par l'intermédiaire du sys.modules
variable ; pour avoir accès à __main__
on peut utiliser sys.modules['__main__']
ou import __main__
il est parfaitement acceptable d'accéder et d'assigner des attributs à cet endroit ; ils apparaîtront comme des variables dans la portée globale du module principal.
Si un nom est assigné dans la portée courante (sauf dans la portée de la classe), il sera considéré comme appartenant à cette portée, sinon il sera considéré comme appartenant à toute portée englobante qui assigne à la variable (elle peut ne pas être encore assignée, ou pas du tout), ou enfin à la portée globale. Si la variable est considérée comme locale, mais qu'elle n'est pas encore assignée, ou qu'elle a été supprimée, la lecture de la valeur de la variable donnera le résultat suivant UnboundLocalError
qui est une sous-classe de NameError
.
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
La portée peut déclarer qu'elle veut explicitement modifier la variable globale (portée du module), avec le mot clé global :
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
Cela est également possible même si elle a été occultée dans la portée englobante :
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
Dans python 2, il n'y a pas de moyen facile de modifier la valeur dans la portée englobante ; généralement, cela est simulé en ayant une valeur mutable, telle qu'une liste avec une longueur de 1 :
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
Cependant, dans python 3, l'option nonlocal
vient à la rescousse :
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
En nonlocal
documentation dit que
Les noms énumérés dans une déclaration non locale, contrairement à ceux énumérés dans une déclaration globale, doivent faire référence à des liaisons préexistantes dans une portée englobante (la portée dans laquelle une nouvelle liaison doit être créée ne peut être déterminée sans ambiguïté).
c'est-à-dire nonlocal
fait toujours référence à l'étendue non globale extérieure la plus proche dans laquelle le nom a été lié (c'est-à-dire assigné, y compris utilisé en tant qu'attribut de l'attribut for
variable cible, dans le with
ou en tant que paramètre de fonction).
Toute variable qui n'est pas considérée comme étant locale à la portée actuelle, ou à toute portée englobante, est une variable globale. Le nom d'une variable globale est recherché dans le dictionnaire global du module ; s'il n'est pas trouvé, la variable globale est alors recherchée dans le module builtins ; le nom du module a été modifié de python 2 à python 3 ; dans python 2, il s'agissait de __builtin__
et dans python 3, il est maintenant appelé builtins
. Si vous assignez à un attribut du module builtins, il sera visible par la suite à n'importe quel module comme une variable globale lisible, à moins que ce module ne l'ombrage avec sa propre variable globale avec le même nom.
La lecture du module intégré peut également s'avérer utile ; supposons que vous souhaitiez utiliser la fonction print de python 3 dans certaines parties du fichier, mais que d'autres parties du fichier utilisent toujours la fonction print de python 3. print
déclaration. Dans Python 2.6-2.7, vous pouvez vous procurer la version Python 3 print
fonction avec :
import __builtin__
print3 = __builtin__.__dict__['print']
En from __future__ import print_function
n'importe pas réellement le print
dans Python 2 - au lieu de cela, elle désactive simplement les règles d'analyse syntaxique pour la fonction print
dans le module actuel, en traitant print
comme n'importe quel autre identifiant de variable, et permettant ainsi à la print
la fonction soit recherchée dans les builtins.
2 votes
Les règles de cadrage sont décrites de manière assez succincte - mais aussi complète - dans la documentation Python : docs.python.org/3/reference/ .