2013-04-11 145 views
50

我已经跑入了一个在Python脚本中导入模块的墙壁。我会尽我所能来描述错误,为什么我会遇到它,以及为什么我要搭配这种特殊的方法来解决我的问题(我将在第二秒中描述):Python - 导入模块中全局变量的可见性

让我们假设我有一个模块其中我定义一些效用函数/类,其是指在向其中该辅助模块将被导入的命名空间中定义的实体(让“一”是这样的实体):

模块1:

def f(): 
    print a 

然后我有主程序,其中定义了“a”,我要导入这些实用程序:

import module1 
a=3 
module1.f() 

执行程序会触发以下错误:

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 

过去Similar questions have been asked(前两天,德呃)和几个解决方案已经提出,但是我真的不认为这些符合我的要求。 这里是我的特定上下文:

我试图做一个Python程序连接到MySQL数据库服务器,并显示/修改数据与GUI。为了清晰起见,我在一个单独的文件中定义了一大堆辅助/实用MySQL相关函数。然而它们都有一个公共变量,我最初定义了里面的公用程序模块,而其中的光标对象来自MySQLdb模块。 我后来认识到,光标对象(用于与db服务器通信)应在主模块中定义,以便主模块和导入其中的任何内容都可以访问该对象。

最终结果将是这样的:

utilities_module.py:

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

而我的主要模块:

program.py:

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

然后,只要我尝试调用任何实用程序功能,就会触发a前面提到的“全球名称未定义”错误。

一个特别的建议是有一个 “从程序导入CUR” 语句的程序文件,比如这个:

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 * 

但这是循环导入或类似的东西,底线,它也崩溃了。所以我的问题是:

如何让地狱,我可以让“cur”对象,在主模块中定义,可见的导入到它的辅助功能?

感谢您的时间和我最深的歉意,如果解决方案已发布到别处。我自己找不到答案,我的书里没有更多的技巧。

+1

根据您的更新:您可能不希望单个共享游标。一个共享的_connection_,是的,但是游标很便宜,并且通常有很多理由让多个游标同时存在(例如,所以你可以以锁步方式遍历其中的两个,而不必'fetch_all'并遍历两个列表,或者只是让你有两个不同的线程/ greenlets/callback-chains /不管使用数据库而没有冲突)。 – abarnert 2013-04-11 22:57:47

+0

无论如何,无论你想分享什么,我想这里的答案是将'db'(和'cur',如果你坚持的话)放入一个单独的模块中,'program'和'utilities_module'将它们从中导入。这样你就不会得到循环依赖(从程序导入的模块导入程序)以及随之而来的混乱。 – abarnert 2013-04-11 22:58:50

回答

135

Python中的全局变量与模块不在所有模块中。 (很多人都对此感到困惑,因为在C语言中,除非您明确地将其设置为static,否则全局实际上是相同的。)

根据您的实际使用情况,有多种解决方法。


在甚至走下这条路之前,问问自己这是否真的需要全球化。也许你真的想要一个类,f作为一个实例方法,而不仅仅是一个免费的功能?然后,你可以做这样的事情:

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

如果你确实需要一个全球性的,但它只是在那里通过module1使用,设置该模块中。

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

在另一方面,如果a被一大堆模块的共享,把它放在别的地方,并让每个人都导入:

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

...,并在模块1。潘岳:

import shared_stuff 
def f(): 
    print shared_stuff.a 

不要使用from IM除非该变量是一个常量。 from shared_stuff import a会创建一个新的a变量,该变量已初始化为导入时引用的任何shared_stuff.a,并且此新的a变量不会受到shared_stuff.a分配的影响。


或者,你真的需要它是真正的全球性无处不在,就像一个内置的,将其添加到内置模块极少数情况下。 Python 2.x和3.x的具体细节有所不同。在3.x中,它的工作原理是这样的:

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

不错,全面。 – kindall 2013-04-11 22:05:59

+0

感谢您的回答。我将尝试导入shared_stuff方法,尽管我无法克​​服在主模块中定义的变量不是*真正*全局的事实 - 是不是有任何方法可以让所有人真正可以访问名称,无论从何处该程序? – Nubarke 2013-04-11 22:06:41

+1

有些东西是“任何人都可以访问的,无论程序如何”都非常违背[python](http://www.python.org/dev/peps/pep-0020/),特别是“显式优于隐”。 Python有一个非常好的设计思路,如果你使用得很好,你可能会设法去你的python职业生涯的其余部分,而不需要再次使用global关键字。 – 2013-04-11 22:16:34

3

函数使用模块的全局变量定义为英寸,而不是设置a = 3,例如,应该设置module1.a = 3。所以,如果你想在utilities_module作为全球提供cur,请设置utilities_module.cur

更好的解决方案:不要使用全局变量。将需要的变量传递给需要它的函数,或创建一个类将所有数据捆绑在一起,并在初始化实例时传递它。

3

这篇文章只是对我遇到的Python行为的观察。如果你做了同样的事情,也许你上面阅读的建议不适合你。

即,我有一个包含全局/共享变量的模块(如上面所建议的):

#sharedstuff.py 

globaltimes_randomnode=[] 
globalist_randomnode=[] 

然后,我有其中进口共享东西与主模块:

import sharedstuff as shared 

和一些其他模块,实际上填充这些数组。这些被主模块调用。退出这些其他模块时,我可以清楚地看到数组已填充。但是在主模块中阅读时,它们是空的。这对我来说很奇怪(嗯,我是Python新手)。但是,当我改变我的方式导入sharedstuff.py主要模块中:

from globals import * 

它的工作(被填充的阵列)。

只是说

2

这一特定问题最简单的办法将是该会存储光标在全球变化到模块的模块中添加其他功能。然后所有其他功能也可以使用它。

模块1:

cursor = None 

def setCursor(cur): 
    global cursor 
    cursor = cur 

def method(some, args): 
    global cursor 
    do_stuff(cursor, some, args) 

主程序:

import module1 

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

由于全局的模块具体,你可以添加以下功能,所有导入的模块,然后用它来:

  • 添加奇异变量(字典格式)作为全局变量
  • 将您的main模块全局变为 。

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

然后,所有你需要传递当前全局是:

import module

module.addglobals(globals())

3

作为一种变通方法,你可以考虑在外层设置环境变量,就像这样。

main.py:

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

mymodule.py:

import os 
print os.environ['MYVAL'] 

作为额外的预防措施,处理在模块内没有定义MYVAL的情况。