Visibilidad de variables globales en módulos importados.

Resuelto Nubarke asked hace 11 años • 10 respuestas

Me he topado con un problema al importar módulos en un script de Python. Haré lo mejor que pueda 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 entidades definidas en el espacio de nombres al que se importará este módulo auxiliar (sea "a" dicha entidad):

módulo 1:

def f():
    print a

Y luego tengo el programa principal, donde se define "a", al cual quiero importar esas utilidades:

import module1
a=3
module1.f()

La ejecución del programa generará el siguiente error:

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

Se han hecho preguntas similares en el pasado (hace dos días, claro) y se han sugerido varias soluciones, sin embargo, realmente no creo que se ajusten a mis requisitos. Aquí está mi contexto particular:

Estoy intentando crear un programa Python que se conecte a un servidor de base de datos MySQL y muestre/modifique datos con una GUI. Por razones de limpieza, he definido el conjunto de funciones auxiliares/utilitarias relacionadas con MySQL 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 de cursor del módulo MySQLdb. Más tarde me di cuenta de que el objeto cursor (que se utiliza para comunicarse con el servidor de base de datos) debería 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:

utilidades_module.py:

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

Y mi módulo principal:

programa.py:

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

Y luego, tan pronto como intento llamar a cualquiera de las funciones de las utilidades, se activa el error "nombre global no definido" antes mencionado.

Una sugerencia particular fue tener una declaración "from program import cur" en el archivo de utilidades, como esta:

utilidades_module.py:

from program import cur
#rest of function definitions

programa.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 definitiva, también colapsa. Entonces 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 publicó en otro lugar. Simplemente no puedo encontrar la respuesta por mí mismo y no tengo más trucos en mi libro.

Nubarke avatar Apr 12 '13 04:04 Nubarke
Aceptado

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

Hay diferentes formas de resolver esto, según su caso de uso real.


Antes incluso de seguir este camino, pregúntese si realmente es necesario que sea global. ¿Quizás realmente quieras una clase, fcomo 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 solo está ahí para que lo use module1, configúrelo en ese módulo.

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

Por otro lado, si aes compartido por una gran cantidad de módulos, colóquelo 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 fromimportación a menos que la variable esté destinada a ser una constante. from shared_stuff import acrearía una nueva avariable inicializada a cualquier cosa shared_stuff.aa la que se hiciera referencia en el momento de la importación, y esta nueva avariable no se vería afectada por las asignaciones a shared_stuff.a.


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

import builtins
import module1
builtins.a = 3
module1.f()
abarnert avatar Apr 11 '2013 22:04 abarnert

Como solución alternativa, podría considerar configurar variables de entorno en la capa exterior, como esta.

principal.py:

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

mimódulo.py:

import os

myval = None
if 'MYVAL' in os.environ:
    myval = os.environ['MYVAL']

Como precaución adicional, maneje el caso en el que MYVAL no esté definido dentro del módulo.

Vishal avatar Mar 30 '2016 08:03 Vishal

Esta publicación es solo una observación del comportamiento de Python que encontré. Quizás los consejos que leíste arriba no te funcionen si hiciste lo mismo que yo hice a continuación.

Es decir, 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 el material compartido con:

import sharedstuff as shared

y algunos otros módulos que realmente poblaron estos arreglos. Estos son llamados por el módulo principal. Al salir de estos otros módulos puedo ver claramente que las matrices están completas. 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 en que importo Sharedstuff.py en el módulo principal a:

from globals import *

funcionó (las matrices estaban pobladas).

Sólo digo'

user3336548 avatar Apr 17 '2015 13:04 user3336548