Esta pregunta es un seguimiento en a question about Python variable scope. Las preguntas adicionales q1, q2 y answers se pueden encontrar en SO, entre otros. El oficial Python documentation y PEP 3104 se supone que explican los detalles, pero no parecen completamente autoexplicativos para mí.Python no local depende del nivel de jerarquía?
El tema que trato de resolver es refactorizar el código que contiene nonlocal
/global
moviendo ese código arriba/abajo un nivel de jerarquía.
Lo que no entiendo son las implicaciones de esta sentencia de la referencia de Python:
Names listed in a nonlocal statement, unlike to those listed in a global statement, must refer to pre-existing bindings in an enclosing scope (the scope in which a new binding should be created cannot be determined unambiguously).
Dado el siguiente código en el ámbito global:
var = 0
def outer():
global var # line A
var = 1
def inner():
nonlocal var # line B
var = 2
print('inner:', var)
inner()
print('outer:', var)
outer()
print('main:', var)
ejecución genera un error:
SyntaxError: no binding for nonlocal 'var' found
El código funciona (con diferente semántica, Por supuesto, si cualquiera de las líneas A está comentado:
inner: 2
outer: 2
main: 0
o línea B es comentada:
inner: 2
outer: 1
main: 1
Sin embargo, en el ejemplo anterior, y dado que nonlocal
se supone para unirse var a la " encerrando el alcance ", hubiera esperado que la línea A vincule el ámbito externo/var con el ámbito global y la línea B, luego busque outer/var y también vuelva a enlazar inner/var con global/var. En cambio, parece no encontrarlo en absoluto (debido a la reenlace en la línea A, supongo) y generar un error.
El resultado deseado era lo que esperaba:
inner: 2
outer: 2
main: 2
Se trata sólo de un ejemplo más del estado de ánimo confuso de la determinación del alcance en Python?
O, para hacer de esto una cuestión constructiva:
- ¿Cómo puede un ejemplo de ello puede escribir de una manera que no importa en qué nivel reside una función (tener que intercambiar
global
connonlocal
y viceversa)? - Si las funciones residen en un nivel intermedio y desconocido de jerarquía, ¿cómo podría el autor de
outer()
cambiar el código que no se debe tocar el nivel más externo (en este caso global) ni elinner()
? -
En mi humilde comprensión del lenguaje, construcciones como estas (depende de los cierres) deben ser evitadas. Otros ya han sugerido utilizar otras funciones de idioma (classes, func attrs) para lograr este tipo de sensibilidad de contexto.
Las variables globales y locales son fundamentalmente diferentes en Python. Las sentencias 'nonlocal' solo pueden referirse a variables locales de un alcance envolvente y nunca a variables globales; para eso es' global', después de todo. Los conceptos detrás de 'global' y' nonlocal' son bastante diferentes. Sus argumentos sobre cómo el estado actual debería plantear un problema están completamente construidos. Mi respuesta sería: No use variables globales, y no use 'global', y todos los" problemas "mencionados (y algunos más) desaparecerán. –
Aunque generalmente estoy de acuerdo en evitar el uso de globales, otros parecen encontrar el concepto tan útil que Python proporciona la palabra clave 'global' y Py3k incluso agrega un' nonlocal'. Estoy tratando de entender las implicaciones de su uso combinado. – cfi
"... y Py3k incluso agregó un' no local'. " 'nonlocal' está destinado a hacer que los cierres sean más útiles. No está relacionado con variables globales. –