导入模块中全局变量的可见性

Nub*_*rke 88 python namespaces python-2.6 python-import mysql-python

我在Python脚本中遇到了一些导入模块的问题.我将尽我所能来描述错误,为什么我遇到它,以及为什么我要用这种特殊的方法来解决我的问题(我将在一秒钟内描述):

假设我有一个模块,我在其中定义了一些实用函数/类,它们引用了将在其中导入此辅助模块的命名空间中定义的实体(让"a"成为这样的实体):

模块1:

def f():
    print a
Run Code Online (Sandbox Code Playgroud)

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

import module1
a=3
module1.f()
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

过去(两天前,呃)已经提出类似的问题,并提出了几种解决方案,但我并不认为这些问题符合我的要求.这是我的特定背景:

我正在尝试创建一个连接到MySQL数据库服务器并使用GUI显示/修改数据的Python程序.为清洁起见,我在一个单独的文件中定义了一堆辅助/实用的MySQL相关函数.但是它们都有一个公共变量,我最初实用程序模块中定义了它,它是MySQLdb模块中的游标对象.后来我意识到应该在主模块中定义游标对象(用于与数据库服务器通信),这样主模块和导入其中的任何东西都可以访问该对象.

最终结果将是这样的:

utilities_module.py:

def utility_1(args):
    code which references a variable named "cur"
def utility_n(args):
    etcetera
Run Code Online (Sandbox Code Playgroud)

我的主要模块:

program.py:

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

然后,一旦我尝试调用任何实用程序函数,它就会触发上述"全局名称未定义"错误.

一个特别的建议是在实用程序文件中有一个"from program import cur"语句,例如:

utilities_module.py:

from program import cur
#rest of function definitions
Run Code Online (Sandbox Code Playgroud)

program.py:

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

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

我怎么能在主模块中定义的"cur"对象对导入它的那些辅助函数可见?

感谢您的时间和最深的歉意,如果解决方案已在其他地方发布.我自己找不到答案,而且我的书中没有更多技巧.

aba*_*ert 207

Python中的Globals 是模块的全局,而不是所有模块.(许多人对此感到困惑,因为在C语言中,除非您明确指出,否则全局在所有实现文件中都是相同的static.)

根据您的实际使用情况,有不同的方法可以解决这个问题.


在走这条路之前,先问问自己这是否真的需要全球化.也许你真的想要一个类,f作为一个实例方法,而不仅仅是一个自由函数?然后你可以做这样的事情:

import module1
thingy1 = module1.Thingy(a=3)
thingy1.f()
Run Code Online (Sandbox Code Playgroud)

如果你确实想要一个全局,但它只是在那里使用module1,请在该模块中设置它.

import module1
module1.a=3
module1.f()
Run Code Online (Sandbox Code Playgroud)

另一方面,如果a由大量模块共享,则将其放在其他位置,并让每个人都导入它:

import shared_stuff
import module1
shared_stuff.a = 3
module1.f()
Run Code Online (Sandbox Code Playgroud)

......并且,在module1.py中:

import shared_stuff
def f():
    print shared_stuff.a
Run Code Online (Sandbox Code Playgroud)

from除非变量是常量,否则不要使用导入.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()
Run Code Online (Sandbox Code Playgroud)

  • 很好,很全面. (7认同)
  • 让某些东西“从任何程序中都可以被每个人访问”非常违背Python的禅宗](http://www.python.org/dev/peps/pep-0020/),特别是“显式优于隐式” ”。Python 有一个经过深思熟虑的 oo 设计,如果你用得好,你可能会在你余下的 Python 职业生涯中不再需要再次使用 global 关键字。 (2认同)
  • @DanielArmengod:我添加了内置答案,以防您确实需要它。(如果您需要更多详细信息,请搜索 SO;至少有两个关于如何正确向内置函数添加内容的问题。)但是,正如 Bi Rico 所说,您几乎肯定并不真正需要它,或者想要它。 (2认同)

Vis*_*hal 6

作为解决方法,您可以考虑在外层设置环境变量,如下所示.

main.py:

import os
os.environ['MYVAL'] = str(myintvariable)
Run Code Online (Sandbox Code Playgroud)

mymodule.py:

import os

myval = None
if 'MYVAL' in os.environ:
    myval = os.environ['MYVAL']
Run Code Online (Sandbox Code Playgroud)

作为额外的预防措施,处理模块内部未定义MYVAL时的情况.


kin*_*all 5

函数使用其定义模块的全局变量。a = 3例如,应该设置而不是设置module1.a = 3。因此,如果要cur用作全局输入utilities_module,请设置utilities_module.cur

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


小智 5

This post is just an observation for Python behaviour I encountered. Maybe the advices you read above don't work for you if you made the same thing I did below.

Namely, I have a module which contains global/shared variables (as suggested above):

#sharedstuff.py

globaltimes_randomnode=[]
globalist_randomnode=[]
Run Code Online (Sandbox Code Playgroud)

Then I had the main module which imports the shared stuff with:

import sharedstuff as shared
Run Code Online (Sandbox Code Playgroud)

and some other modules that actually populated these arrays. These are called by the main module. When exiting these other modules I can clearly see that the arrays are populated. But when reading them back in the main module, they were empty. This was rather strange for me (well, I am new to Python). However, when I change the way I import the sharedstuff.py in the main module to:

from globals import *
Run Code Online (Sandbox Code Playgroud)

it worked (the arrays were populated).

Just sayin'