Pregunta Funciones locales en Python


En el siguiente código de Python, obtengo un UnboundLocalError. Según tengo entendido, las funciones locales comparten las variables locales de la función contenedora, pero este parece ser el caso aquí. Reconozco eso a es un valor inmutable en este contexto, pero eso no debería ser un problema.

def outer():
    a = 0
    def inner():
        a += 1
    inner()
outer()

Parecería que la función interna ha recibido copias de todas las referencias en la función principal, ya que no obtengo el UnboundLocalError excepción si el valor de a está envuelto en un tipo mutable

¿Alguien puede aclarar el comportamiento aquí y señalarme la documentación apropiada de Python sobre esto?


32
2017-09-12 04:45


origen


Respuestas:


Creo que tienes razón al ver esto como un problema de "mutabilidad". Si bien el código que publicó arroja un "UnboundLocalError", el siguiente código no:

def outer():
    a = 0
    def inner():
        print a
    inner()
outer()

Python no le permite reasignar el valor de una variable desde un ámbito externo en un ámbito interno (a menos que esté utilizando la palabra clave "global", que no se aplica en este caso).

Consulte la sección inferior de la documentación de "clases" en esta documentación de Python 2.6.2:

9.2. Ámbitos y espacios de nombres de Python

[...] Si un nombre es declarado global, entonces todas las referencias y asignaciones van   directamente al alcance medio que contiene los nombres globales del módulo.   De lo contrario, todas las variables que se encuentran fuera del alcance más interno son   de solo lectura (un intento de escribir en dicha variable simplemente creará un   nueva variable local en el ámbito más interno, dejando idénticamente   llamada variable externa sin cambios).

Su "UnboundLocalError" se debe a que su función realmente está declarando una nueva variable llamada "a" y luego tratando de hacer una operación "+ =" sobre ella, pero esto falla porque "a" todavía no tiene un valor. (Ver "a + = 1" como "a = a + 1" y puede ver el problema si "a" no está definido).

En general, si va a querer modificar "a", la forma en que la gente normalmente lo utiliza es usar un tipo mutable para pasar "a" (como una lista o un diccionario). Puede modificar "a" a través del contenido del tipo mutable (como probablemente haya notado en sus pruebas con esta configuración).

¡Espero que ayude!


30
2017-09-12 04:54



Intente vincular la variable como un argumento.

def outer():
    a = 0
    def inner(a=a):
        a += 1

    inner()

outer()

Intentaré desenterrar los documentos apropiados.

editar

Dado que desea que la función interna tenga un efecto secundario en el ámbito externo, entonces necesita usar un tipo de datos mutable como una lista. Los enteros y las cadenas son inmutables.

def outer():
    a = [0]
    def inner():
        a[0] += 1
    inner()
    print a[0]
outer()

8
2017-09-12 04:55



Debe especificar su variable como no local para preservar su estado en el cierre, por lo que la definición debe ser así

def outer():
a = 0
def inner():
    nonlocal a
    a += 1
inner()

8
2018-03-11 08:41