Declaración / palabra clave no local de Python

8 minutos de lectura

avatar de usuario de ooboo
oooo

Que hace nonlocal hacer en Python 3.x?


Para cerrar preguntas de depuración donde OP necesita nonlocal y no se da cuenta, utilice ¿Es posible modificar la variable en python que está en el ámbito externo, pero no global? en cambio.

Aunque Python 2 es oficialmente sin soporte a partir del 1 de enero de 2020si por alguna razón se ve obligado a mantener una base de código de Python 2.x y necesita un equivalente a nonlocalconsulte la palabra clave no local en Python 2.x.

  • Eche un vistazo a esta pregunta: stackoverflow.com/questions/1414304/local-functions-in-python

    – Matt Carpintero

    5 de diciembre de 2010 a las 13:50

  • Aquí está la documentación del sitio web oficial de Python para no local: docs.python.org/3/reference/… (esta documentación ha estado disponible desde Python 3.0, por lo que la afirmación del OP de que no hay documentación oficial fue simplemente incorrecta)

    – wkschwartz

    3 oct 2013 a las 17:46


  • "There is no documentation for nonlocal". En realidad, puedes hacer help(keyword_in_string) para documentaciones en Python 3 y superior

    – rassa45

    7 de agosto de 2015 a las 9:21


  • Para ser justos, los documentos oficiales apestan sobre el tema. El ejemplo de la respuesta seleccionada deja las cosas muy claras, lo que hace que esta sea una pregunta valiosa.

    – Físico loco

    27 mayo 2016 a las 20:14

  • En el tutorial oficial de Python hay un buena explicación del concepto de ámbitos y espacios de nombres con un buen ejemplo.

    – jamón

    8 de octubre de 2016 a las 6:03


Avatar de usuario de Anon
Luego

Compara esto, sin usar 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

A esto, usando nonlocaldónde inner()‘s x es ahora también 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 tuviéramos que usar globalse uniría x al valor propiamente “global”:

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

  • Es muy similar, pero tenga en cuenta que la x externa no es global en el ejemplo, sino que se define en la función externa.

    – Anónimo

    11 de agosto de 2009 a las 18:04

  • @Dustin: en realidad, si tuviera la clase A con un atributo x y una subclase B definida en ella, se referiría a x desde B como Ax

    – Anónimo

    11 de agosto de 2009 a las 18:37

  • El código se sangra fácilmente al definir funciones internas y termina violando la recomendación PEP8 de 79 caracteres. ¿Alguna forma de evitar este problema? ¿Puede una función interna colocarse de alguna manera fuera de la función externa? Sé que la pregunta suena estúpida, pero lo digo en serio.

    – tommy.carstensen

    12 de febrero de 2015 a las 0:03

  • @ tommy.carstensen podría pasar la función como un argumento que es la belleza de las funciones de orden superior. También en la programación funcional esto se llama composición, python no es un lenguaje FP puro pero ciertamente puedes jugar con características (generadores, funciones de orden superior son algunos ejemplos)

    – superusuarioi

    30 de marzo de 2015 a las 21:24


  • ¿Qué pasa si hay 3 funciones anidadas? Entonces, ¿hay alguna forma de acceder a los 4 niveles desde la función más interna?

    – Rastapopoulos

    9 oct 2020 a las 12:11


En resumen, le permite asignar valores a una variable en un ámbito externo (pero no global). Ver PEP 3104 por todos los detalles sangrientos.

Una búsqueda en Google de “python no local” arrojó la propuesta, PEP 3104, que describe completamente la sintaxis y el razonamiento detrás de la declaración. en resumen, funciona exactamente de la misma manera que el global instrucción, excepto que se utiliza para referirse a variables que no son ni globales ni locales para la función.

He aquí un breve ejemplo de lo que puede hacer con esto. El generador de contador se puede reescribir para usar esto, de modo que se parezca más a las expresiones idiomáticas de los idiomas con cierres.

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

Obviamente, podrías escribir esto como un generador, como:

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

Pero Si bien esto es Python perfectamente idiomático, parece que la primera versión sería un poco más obvia para los principiantes. Usar correctamente los generadores, llamando a la función devuelta, es un punto común de confusión. La primera versión devuelve explícitamente una función.

  • Estaba seguro de que eso es lo que hace la palabra clave ‘global’: funciona en entornos más altos hasta que llega a una variable con ese nombre. una variable x podría declararse a nivel de módulo, dentro de una clase, luego por separado en una función dentro de esta clase y luego en una función interna de esa función. ¿Cómo sabe a qué x referirse?

    – ooo

    11 de agosto de 2009 a las 17:54

  • lo que pasa con global es que solo funciona para variables globales. no puede ver variables en un ámbito no global envolvente.

    – Eliminación de negación simple

    11 de octubre de 2009 a las 3:53

  • Probé make_counter; sin embargo, no devuelve un generador sino una función. ¿Hay alguna manera de devolver un generador para que luego pueda iterarlo?

    – Dejell

    5 de diciembre de 2013 a las 17:23

  • @Dejel: este ejemplo pretende ilustrar el nonlocal declaración en Python; Si desea una secuencia de números naturales, el idioma de Python es en realidad itertools.count()

    – Eliminación de negación simple

    5 de diciembre de 2013 a las 17:28

  • Me gustaría demostrar la capacidad de devolver un generador como con yield – yield en realidad devuelve un generador. Mi idea no es usar el rendimiento y, en su lugar, usar una solución no local u otra

    – Dejell

    5 de diciembre de 2013 a las 17:40

Avatar de usuario de Danny Milosavljevic
Danny Milosavljevic

Toma el “más cercano” al punto de referencia en el código fuente. Esto se llama “Alcance léxico” y es estándar desde hace más de 40 años.

Los miembros de la clase de Python están realmente en un diccionario llamado __dict__ y nunca será alcanzado por el alcance léxico.

Si no especificas nonlocal pero hazlo x = 7, creará una nueva variable local “x”. Si especificas nonlocal, encontrará la “x” “más cercana” y la asignará. si especificas nonlocal y no hay “x”, le dará un mensaje de error.

la palabra clave global siempre me ha parecido extraño ya que felizmente ignorará todas las demás “x” excepto la más externa.

Avatar de usuario de Yossi Truzman
yossi truzman

ayuda (‘no local’) El nonlocal declaración


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

los nonlocal hace que los identificadores enumerados se refieran a variables vinculadas previamente en el ámbito de inclusión más cercano. Esto es importante porque el comportamiento predeterminado para el enlace es buscar primero en el espacio de nombres local. La declaración permite que el código encapsulado vuelva a enlazar variables fuera del ámbito local además del ámbito global (módulo).

Nombres enumerados en un nonlocal declaración, a diferencia de los enumerados en un
global declaración, debe hacer referencia a enlaces preexistentes en un ámbito envolvente (el ámbito en el que se debe crear un nuevo enlace no se puede determinar sin ambigüedades).

Nombres enumerados en un nonlocal La declaración no debe entrar en conflicto con enlaces preexistentes en el ámbito local.

Ver también:

PEP 3104 – Acceso a nombres en ámbitos externos
La especificación para el nonlocal declaración.

Temas de ayuda relacionados: global, NAMESPACES

Fuente: Referencia del lenguaje Python

  • Aprenda algo nuevo cada día. No tenía idea de que podrías usar help() en palabras clave (y ahora mi mente está alucinada: help() sin argumentos va interactivo).

    – Erik Youngren

    24 de febrero de 2014 a las 9:05

Cita de la Referencia de Python 3:

La instrucción no local hace que los identificadores enumerados se refieran a variables vinculadas previamente en el ámbito envolvente más cercano, excluyendo los globales.

Como se dijo en la referencia, en el caso de varias funciones anidadas, solo se modifica la variable en la función envolvente más cercana:

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 “más cercana” puede estar a varios niveles de distancia:

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

Pero no puede ser una variable global:

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

  • Aprenda algo nuevo cada día. No tenía idea de que podrías usar help() en palabras clave (y ahora mi mente está alucinada: help() sin argumentos va interactivo).

    – Erik Youngren

    24 de febrero de 2014 a las 9:05

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)

¿Ha sido útil esta solución?