Visibilidad de variables globales en módulos importados.

Me he topado con un poco de una pared de módulos de importación en un script de Python. Haré todo lo posible para describir el error, por qué lo encuentro y por qué estoy vinculando este enfoque particular para resolver mi problema (que describiré en un segundo):

Supongamos que tengo un módulo en el que he definido algunas funciones / clases de utilidad, que se refieren a las entidades definidas en el espacio de nombres en el que se importará este módulo auxiliar (deje que “a” sea una entidad de este tipo):

módulo 1:

def f(): print a 

Y luego tengo el progtwig principal, donde se define “a”, en el que quiero importar esas utilidades:

 import module1 a=3 module1.f() 

La ejecución del progtwig activará el siguiente error:

 Traceback (most recent call last): File "Z:\Python\main.py", line 10, in  module1.f() File "Z:\Python\module1.py", line 3, in f print a NameError: global name 'a' is not defined 

Se hicieron preguntas similares en el pasado (hace dos días, por cierto) y se sugirieron varias soluciones, sin embargo, realmente no creo que estas se ajusten a mis necesidades. Aquí está mi contexto particular:

Estoy intentando crear un progtwig Python que se conecta a un servidor de base de datos MySQL y muestra / modifica los datos con una GUI. En aras de la limpieza, he definido el conjunto de funciones relacionadas con MySQL auxiliares / utilidades en un archivo separado. Sin embargo, todos tienen una variable común, que había definido originalmente dentro del módulo de utilidades, y que es el objeto del cursor desde el módulo MySQLdb. Más tarde, me di cuenta de que el objeto del cursor (que se utiliza para comunicarse con el servidor de la base de datos) debe definirse en el módulo principal, de modo que tanto el módulo principal como cualquier cosa que se importe en él puedan acceder a ese objeto.

El resultado final sería algo como esto:

utilities_module.py:

 def utility_1(args): code which references a variable named "cur" def utility_n(args): etcetera 

Y mi módulo principal:

program.py:

 import MySQLdb, Tkinter db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import * 

Y luego, tan pronto como bash llamar a cualquiera de las funciones de utilidades, se dispara el error mencionado anteriormente “nombre global no definido”.

Una sugerencia particular fue tener una statement “desde el progtwig de importación cur” en el archivo de utilidades, como esto:

utilities_module.py:

 from program import cur #rest of function definitions 

program.py:

 import Tkinter, MySQLdb db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined! from utilities_module import * 

Pero eso es una importación cíclica o algo así y, en el fondo, también se bloquea. Así que mi pregunta es:

¿Cómo diablos puedo hacer que el objeto “cur”, definido en el módulo principal, sea visible para las funciones auxiliares que se importan en él?

Gracias por su tiempo y mis más sinceras disculpas si la solución se ha publicado en otro lugar. Simplemente no puedo encontrar la respuesta y no tengo más trucos en mi libro.

Los globales en Python son globales para un módulo , no para todos los módulos. (Muchas personas están confundidas por esto, porque en, digamos, C, un global es el mismo en todos los archivos de implementación, a menos que lo haga explícitamente static ).

Hay diferentes maneras de resolver esto, dependiendo de su caso de uso real.


Antes de seguir este camino, pregúntese si esto realmente necesita ser global. ¿Tal vez realmente quieres una clase, con f como método de instancia, en lugar de solo una función gratuita? Entonces podrías hacer algo como esto:

 import module1 thingy1 = module1.Thingy(a=3) thingy1.f() 

Si realmente desea un global, pero está ahí para ser utilizado por el module1 , module1 en ese módulo.

 import module1 module1.a=3 module1.f() 

Por otro lado, si a es compartido por una gran cantidad de módulos, póngalo en otro lugar y haga que todos lo importen:

 import shared_stuff import module1 shared_stuff.a = 3 module1.f() 

… y, en module1.py:

 import shared_stuff def f(): print shared_stuff.a 

No utilice una importación from menos que la variable sea una constante. from shared_stuff import a crearía una nueva variable inicializada a cualquier shared_stuff.a al que se shared_stuff.a referencia en el momento de la importación, y esta nueva variable no se vería afectada por las asignaciones a shared_stuff.a .


O, en el raro caso de que realmente necesite que sea verdaderamente global en todas partes, como un componente incorporado, agréguelo al módulo incorporado. Los detalles exactos difieren entre Python 2.xy 3.x. En 3.x, funciona así:

 import builtins import module1 builtins.a = 3 module1.f() 

Como solución alternativa, podría considerar establecer variables de entorno en la capa externa, de esta manera.

main.py:

 import os os.environ['MYVAL'] = str(myintvariable) 

mymodule.py:

 import os print os.environ['MYVAL'] 

Como precaución adicional, maneje el caso cuando MYVAL no está definido dentro del módulo.

Una función utiliza las variables globales del módulo en el que se define . En lugar de establecer a = 3 , por ejemplo, debería configurar module1.a = 3 . Por lo tanto, si desea que cur esté disponible como global en utilities_module , configure utilities_module.cur .

Una mejor solución: no usar globals. Pase las variables que necesita a las funciones que lo necesitan, o cree una clase para agrupar todos los datos, y pásela al inicializar la instancia.

Esta publicación es solo una observación del comportamiento de Python que encontré. Tal vez los consejos que lees arriba no te funcionen si hiciste lo mismo que hice a continuación.

A saber, tengo un módulo que contiene variables globales / compartidas (como se sugirió anteriormente):

 #sharedstuff.py globaltimes_randomnode=[] globalist_randomnode=[] 

Luego tuve el módulo principal que importa las cosas compartidas con:

 import sharedstuff as shared 

y algunos otros módulos que realmente poblaron estas matrices. Estos son llamados por el módulo principal. Al salir de estos otros módulos puedo ver claramente que las matrices están pobladas. Pero al volver a leerlos en el módulo principal, estaban vacíos. Esto fue bastante extraño para mí (bueno, soy nuevo en Python). Sin embargo, cuando cambio la forma de importar el sharedstuff.py en el módulo principal para:

 from globals import * 

funcionó (las matrices estaban pobladas).

Sólo digo’

La solución más fácil a este problema en particular hubiera sido agregar otra función dentro del módulo que hubiera almacenado el cursor en una variable global para el módulo. Entonces todas las otras funciones podrían usarlo también.

módulo 1:

 cursor = None def setCursor(cur): global cursor cursor = cur def method(some, args): global cursor do_stuff(cursor, some, args) 

progtwig principal:

 import module1 cursor = get_a_cursor() module1.setCursor(cursor) module1.method() 

Dado que los indicadores globales son específicos del módulo, puede agregar la siguiente función a todos los módulos importados y luego usarla para:

  • Agregue variables singulares (en formato de diccionario) como globales para aquellas
  • Transfiere tu módulo principal a él.

addglobals = lambda x: globals (). update (x)

Entonces, todo lo que necesitas para transmitir los globales actuales es:

módulo de importación

module.addglobals (globals ())

Como no lo he visto en las respuestas anteriores, pensé que agregaría mi solución alternativa simple, que es simplemente agregar un argumento global_dict a la función que requiere las funciones globales del módulo de llamada, y luego pasar el dictado a la función cuando se realiza la llamada; p.ej:

 # external_module def imported_function(global_dict=None): print(global_dict["a"]) # calling_module a = 12 from external_module import imported_function imported_function(global_dict=globals()) >>> 12