Dado el siguiente código:
def A() :
b = 1
def B() :
# I can access 'b' from here.
print( b )
# But can i modify 'b' here? 'global' and assignment will not work.
B()
A()
Porque el código en la B()
función variable b
está en el alcance externo, pero no en el alcance global. ¿Es posible modificar la b
variable desde dentro de la B()
función? Seguro que puedo leerlo desde aquí y print()
, pero ¿cómo modificarlo?
python
python-2.7
grigoryvp
fuente
fuente
b
sea mutable. Una asignación ab
enmascarará el alcance externo.nonlocal
no se ha actualizado a 2.x. Es una parte intrínseca del soporte de cierre.Respuestas:
Python 3.x tiene la
nonlocal
palabra clave . Creo que esto hace lo que quieres, pero no estoy seguro de si estás ejecutando Python 2 o 3.Para python 2, generalmente solo uso un objeto mutable (como una lista o dict) y muto el valor en lugar de reasignarlo.
ejemplo:
Salidas:
fuente
class nonlocal: pass
en el ámbito externo. Luegononlocal.x
se puede asignar a en el ámbito interno.SyntaxError
.NonLocal
¿ Quizás ?Nonlocal
,? :-)Puede usar una clase vacía para contener un ámbito temporal. Es como el mutable pero un poco más bonito.
Esto produce el siguiente resultado interactivo:
fuente
Soy un poco nuevo en Python, pero he leído un poco sobre esto. Creo que lo mejor que obtendrá es similar a la solución alternativa de Java, que consiste en envolver su variable externa en una lista.
Editar: Supongo que esto probablemente era cierto antes de Python 3. Parece que
nonlocal
es tu respuesta.fuente
No, no puedes, al menos de esta manera.
Porque la "operación set" creará un nuevo nombre en el ámbito actual, que cubre el exterior.
fuente
Para cualquiera que vea esto mucho más tarde, una solución alternativa más segura pero más pesada es. Sin necesidad de pasar variables como parámetros.
fuente
La respuesta corta que simplemente funcionará automágicamente
Creé una biblioteca de Python para resolver este problema específico. Se lanza bajo la falta de escucha, así que úselo como desee. Puede instalarlo
pip install seapie
o consultar la página de inicio aquí https://github.com/hirsimaki-markus/SEAPIEuser@pc:home$ pip install seapie
salidas
los argumentos tienen el siguiente significado:
B()
, 1 significa padreA()
y 2 significa abuelo<module>
también conocido como globalLa respuesta larga
Esto es más complicado. Seapie funciona editando los marcos en la pila de llamadas usando la api CPython. CPython es el estándar de facto, por lo que la mayoría de la gente no tiene que preocuparse por ello.
Las palabras mágicas que probablemente te interesen más si estás leyendo esto son las siguientes:
Esto último obligará a las actualizaciones a pasar al ámbito local. Sin embargo, los ámbitos locales se optimizan de manera diferente al ámbito global, por lo que la introducción de nuevos objetos tiene algunos problemas cuando intenta llamarlos directamente si no se inicializan de ninguna manera. Copiaré algunas formas de eludir estos problemas de la página de github
Si siente que el uso
exec()
no es algo con lo que quiera ir, puede emular el comportamiento actualizando el diccionario local verdadero (no el devuelto por locals ()). Copiaré un ejemplo de https://faster-cpython.readthedocs.io/mutable.htmlSalida:
fuente
No creo que debas querer hacer esto. Las funciones que pueden alterar cosas en su contexto circundante son peligrosas, ya que ese contexto puede escribirse sin el conocimiento de la función.
Puede hacerlo explícito, ya sea haciendo de B un método público y C un método privado en una clase (probablemente la mejor manera); o usando un tipo mutable como una lista y pasándolo explícitamente a C:
fuente
nonlocal
palabra clave, pero depende de ti usarla con mucha precaución.Puede, pero tendrá que usar la declaración global (no es una solución realmente buena como siempre cuando se usan variables globales, pero funciona):
fuente
No sé si hay un atributo de una función que da el
__dict__
del espacio exterior de la función cuando este espacio exterior no es el espacio global == el módulo, que es el caso cuando la función es una función anidada, en Python 3.Pero en Python 2, hasta donde yo sé, no existe tal atributo.
Entonces, las únicas posibilidades para hacer lo que quieras son:
1) usar un objeto mutable, como dicen otros
2)
resultado
.
No un
La solución de Cédric Julien tiene un inconveniente:
resultado
La b global después de la ejecución de
A()
se ha modificado y puede que no se deseeEse es el caso solo si hay un objeto con el identificador b en el espacio de nombres global
fuente