如何在Python中创build模块范围的variables?

有没有办法在模块内设置一个全局variables? 当我试图这样做的最明显的方式,如下所示,Python解释器说variables__DBNAME__不存在。

 ... __DBNAME__ = None def initDB(name): if not __DBNAME__: __DBNAME__ = name else: raise RuntimeError("Database name has already been set.") ... 

然后在不同的文件中导入模块

 ... import mymodule mymodule.initDB('mydb.sqlite') ... 

回溯是: UnboundLocalError: local variable '__DBNAME__' referenced before assignment

有任何想法吗? 我试图通过使用一个模块来build立一个单身人士,根据这个人的build议。

这是怎么回事。

首先,Python真正具有的唯一全局variables是模块范围的variables。 你不能做一个真正的全球variables, 你所能做的就是在特定的范围内做一个variables。 (如果你在Python解释器中创build一个variables,然后导入其他模块,那么你的variables是在最外层的范围内,因此在Python会话中是全局的)。

你只需要做一个模块全局variables就可以指定一个名字。

设想一个名为foo.py的文件,包含这一行:

 X = 1 

现在想象你导入它。

 import foo print(foo.X) # prints 1 

不过,让我们假设你想在你的例子中使用你的一个模块范围variables作为一个全局函数。 Python的默认是假定函数variables是本地的。 您只需在您的函数中添加global声明,然后再尝试使用全局函数。

 def initDB(name): global __DBNAME__ # add this line! if __DBNAME__ is None: # see notes below; explicit test for None __DBNAME__ = name else: raise RuntimeError("Database name has already been set.") 

顺便说一句,对于这个例子,简单的if not __DBNAME__testing是足够的,因为除了空string以外的任何string值将评估真,所以任何实际的数据库名称将评估真实。 但是对于可能包含一个可能为0的数字值的variables,您不能仅仅说出if not variablename ; 在这种情况下,您应该使用is运算符明确地testingNone 。 我修改了这个例子来添加一个明确的Nonetesting。 None的显式testing永远不会错,所以我默认使用它。

最后,正如其他人在这个页面上注意到的那样,两个主要的下划线向Python发出信号,表示你希望variables对模块是“私有的”。 如果你曾经import * from mymodule进行import * from mymodule ,Python将不会在你的名字空间中引入带有两个前导下划线的名字。 但是,如果你只是做一个简单的import mymodule ,然后说dir(mymodule)你会看到列表中的“私人”variables,如果你显式引用mymodule.__DBNAME__ Python不会在乎,它只会让你参考它。 双引号下划线是你的模块的用户的一个重要线索,你不希望他们把这个名字重新绑定到他们自己的某个值。

在Python中被认为是最好的做法,不要做import * ,而是通过使用mymodule.something或者通过显式地from mymodule import something ,最大限度地减less耦合和最大化显式性。

编辑:如果出于某种原因,你需要在一个非常旧的版本的Python中没有global关键字这样做,有一个简单的解决方法。 不是直接设置模块全局variables,而是在模块全局级别使用可变types,并将值存储在其中。

在你的函数中,全局variables名将是只读的; 您将无法重新绑定实际的全局variables名称。 (如果你在你的函数中赋值给variables名,它只会影响函数内部的局部variables名)。但是你可以使用这个局部variables名访问实际的全局对象,并将数据存储在其中。

你可以使用一个list但是你的代码会很丑陋:

 __DBNAME__ = [None] # use length-1 list as a mutable # later, in code: if __DBNAME__[0] is None: __DBNAME__[0] = name 

dict更好。 但最方便的是一个类实例,你可以使用一个普通的类:

 class Box: pass __m = Box() # m will contain all module-level values __m.dbname = None # database name global in module # later, in code: if __m.dbname is None: __m.dbname = name 

(你并不需要大写数据库名称variables。)

我喜欢使用__m.dbname而不是__m["DBNAME"]的语法糖; 在我看来,这似乎是最方便的解决scheme。 但dict解决scheme也正常工作。

使用dict你可以使用任何可sorting的值作为关键字,但是当你对有效标识符的名字感到满意的时候,你可以在上面使用一个像Box这样的普通类。

通过在模块上显式访问模块级variables,显式访问模块级variables


简而言之:这里描述的技术与steveha的回答是一样的 , 除了没有人工辅助对象被创build来显式地限定variables的范围。 相反,模块对象本身被赋予了一个variables指针,因此提供了从任何地方访问的显式范围。 (如本地function范围内的分配)

把它看作是当前模块的 自我而不是当前的实例!

 # db.py import sys # this is a pointer to the module object instance itself. this = sys.modules[__name__] # we can explicitly make assignments on it this.db_name = None def initialize_db(name): if (this.db_name is None): # also in local function scope. no scope specifier like global is needed this.db_name = name # also the name remains free for local use db_name = "Locally scoped db_name variable. Doesn't do anything here." else: msg = "Database is already initialized to {0}." raise RuntimeError(msg.format(this.db_name)) 

由于模块被caching,因此只能导入一次 , 所以可以根据需要在多个客户端上经常导入db.py ,并操作相同的通用状态:

 # client_a.py import db db.initialize_db('mongo') 
 # client_b.py from db import db_name if (db_name == 'mongo'): db_name = None 

自从我find它以来,我已经使用这个配方来创build简单和轻量级的处理程序模块 (而不是处理程序类) 。 作为一个额外的奖励,我发现它非常pythonic整体,因为它很好地符合Pythons 明确的政策比隐含的更好

史蒂芬哈的回答对我很有帮助,但是省略了一个重要的观点(我认为这个观点很尴尬)。 如果只访问但不在函数中分配variables,则全局关键字不是必需的。

如果你赋值的variables没有全局关键字,那么Python会创build一个新的局部variables – 模块variables的值将被隐藏在函数内部。 使用global关键字在函数内分配模块var。

在Python 2.7下的Pylint 1.3.1强制不使用全局,如果你不分配变种。

 module_var = '/dev/hello' def readonly_access(): connect(module_var) def readwrite_access(): global module_var module_var = '/dev/hello2' connect(module_var) 

为此,您需要将variables声明为全局variables。 但是,也可以使用module_name.var_name从模块外部访问全局variables。 添加这个作为你的模块的第一行:

 global __DBNAME__ 

你正在陷入一个微妙的怪癖。 您不能在python函数中重新分配模块级别的variables。 我认为这是为了防止人们不小心重新分配一个函数内的东西。

你可以访问模块命名空间,你不应该尝试重新分配。 如果你的函数指定了一些东西,它会自动成为一个函数variables – 而python不会在模块名称空间中查找。

你可以做:

 __DB_NAME__ = None def func(): if __DB_NAME__: connect(__DB_NAME__) else: connect(Default_value) 

但不能在函数内重新分配__DB_NAME__

一种解决方法:

 __DB_NAME__ = [None] def func(): if __DB_NAME__[0]: connect(__DB_NAME__[0]) else: __DB_NAME__[0] = Default_value 

请注意,我不重新分配__DB_NAME__ ,我只是修改其内容。