web-dev-qa-db-fra.com

Déclaration non locale en python

Que fait l’instruction Python nonlocal (dans Python 3.0 et versions ultérieures)? 

Il n'y a pas de documentation sur le site Web officiel de Python et help("nonlocal") ne fonctionne pas non plus.

236
ooboo

Comparez ceci sans utiliser nonlocal:

x = 0
def outer():
    x = 1
    def inner():
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 0

Pour cela, utiliseznonlocal, où inner() 's x est maintenant aussi outer()' s x:

x = 0
def outer():
    x = 1
    def inner():
        nonlocal x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 2
# global: 0

Si nous utilisionsglobal, cela relierait x à la valeur proprement "globale":

x = 0
def outer():
    x = 1
    def inner():
        global x
        x = 2
        print("inner:", x)

    inner()
    print("outer:", x)

outer()
print("global:", x)

# inner: 2
# outer: 1
# global: 2
359
Anon

En bref, cela vous permet d'affecter des valeurs à une variable dans une étendue externe (mais non globale). Voir PEP 3104 pour tous les détails sanglants. 

73
Arkady

Une recherche sur Google pour "python nonlocal" a abouti à la proposition, PEP 3104 , qui décrit de manière complète la syntaxe et le raisonnement sous-tendant l'instruction. En bref, elle fonctionne exactement de la même manière que l’instruction global, sauf qu’elle est utilisée pour faire référence à des variables qui ne sont ni globales ni locales à la fonction. 

Voici un bref exemple de ce que vous pouvez faire avec cela. Le générateur de compteurs peut être réécrit pour l'utiliser de sorte qu'il ressemble davantage aux idiomes des langues avec des fermetures.

def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

Évidemment, vous pourriez écrire ceci en tant que générateur, comme:

def counter_generator():
    count = 0
    while True:
        count += 1
        yield count

Mais bien que ce soit un python parfaitement idiomatique, il semble que la première version serait un peu plus évidente pour les débutants. Utiliser correctement les générateurs, en appelant la fonction retournée, est un point commun de confusion. La première version renvoie explicitement une fonction.

37

help ('nonlocal') La déclaration nonlocal


    nonlocal_stmt ::= "nonlocal" identifier ("," identifier)*

L'instruction nonlocal fait en sorte que les identificateurs répertoriés fassent référence à variables précédemment liées dans la portée englobante la plus proche. C'est important parce que le comportement par défaut pour la liaison est de rechercher le fichier espace de noms local en premier. L'instruction permet au code encapsulé de relier des variables en dehors de la portée locale en plus de la variable globale (module) portée.

Noms répertoriés dans une instruction nonlocal, contrairement à ceux répertoriés dans un global statement, doit faire référence à des liaisons préexistantes dans un fichier champ englobant (le champ dans lequel une nouvelle liaison doit être créée ne peut pas être déterminé sans ambiguïté).

Les noms énumérés dans une instruction nonlocal ne doivent pas entrer en collision avec pre - liaisons existantes dans la portée locale.

Voir également:

PEP 3104 - Accès aux noms dans les étendues externes
La spécification de l'instruction nonlocal.

Rubriques d'aide connexes: global, NAMESPACES

Source: Référence du langage Python

14
Yossi Truzman

@ooboo:

Il prend celui "le plus proche" du point de référence dans le code source . Ceci est appelé "cadrage lexical" et est standard depuis plus de 40 ans.

Les membres de la classe Python sont vraiment dans un dictionnaire appelé __dict__ et ne seront jamais atteints par la portée lexicale.

Si vous ne spécifiez pas nonlocal mais faites x = 7, il créera une nouvelle variable locale "x" . Si vous spécifiez nonlocal, il recherchera le "plus proche" "x" et lui assignera cette variable . Si vous spécifiez nonlocal et il n'y a pas de "x", cela vous donnera un message d'erreur.

Le mot clé global m’a toujours paru étrange dans la mesure où il ignorera avec joie tous les autres "x" à l’exception du plus externe. Bizarre.

13
a = 0    #1. global variable with respect to every function in program

def f():
    a = 0          #2. nonlocal with respect to function g
    def g():
        nonlocal a
        a=a+1
        print("The value of 'a' using nonlocal is ", a)
    def h():
        global a               #3. using global variable
        a=a+5
        print("The value of a using global is ", a)
    def i():
        a = 0              #4. variable separated from all others
        print("The value of 'a' inside a function is ", a)

    g()
    h()
    i()
print("The value of 'a' global before any function", a)
f()
print("The value of 'a' global after using function f ", a)
3
gxyd

Ma compréhension personnelle de la déclaration "nonlocal" (et je m'excuse car je suis novice en Python et en Programmation en général) est que le "non local" est un moyen d'utiliser la fonctionnalité Global dans des fonctions itérées plutôt que dans le corps du code . Une déclaration globale entre les fonctions si vous voulez.

2
Yossi Truzman

Citation de Référence Python 3 :

L'instruction non locale amène les identificateurs répertoriés à faire référence à des variables précédemment liées dans la portée englobante la plus proche, à l'exclusion des globales.

Comme indiqué dans la référence, dans le cas de plusieurs fonctions imbriquées, seule la variable dans la fonction englobante la plus proche est modifiée:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        x = 2
        innermost()
        if x == 3: print('Inner x has been modified')

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Inner x has been modified

La variable "la plus proche" peut être située à plusieurs niveaux:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    x = 1
    inner()
    if x == 3: print('Outer x has been modified')

x = 0
outer()
if x == 3: print('Global x has been modified')

# Outer x has been modified

Mais cela ne peut pas être une variable globale:

def outer():
    def inner():
        def innermost():
            nonlocal x
            x = 3

        innermost()

    inner()

x = 0
outer()
if x == 3: print('Global x has been modified')

# SyntaxError: no binding for nonlocal 'x' found
1
Jeyekomon

avec des fonctions internes 'non locales' (c'est-à-dire des fonctions internes imbriquées), vous pouvez obtenir les droits de lecture & 'write' permission pour cette variable spécifique de la fonction parent externe. Et nonlocal ne peut être utilisé qu’à l’intérieur des fonctions interneseg:

a = 10
def Outer(msg):
    a = 20
    b = 30
    def Inner():
        c = 50
        d = 60
        print("MU LCL =",locals())
        nonlocal a
        a = 100
        ans = a+c
        print("Hello from Inner",ans)       
        print("value of a Inner : ",a)
    Inner()
    print("value of a Outer : ",a)

res = Outer("Hello World")
print(res)
print("value of a Global : ",a)
0
NIPHIN