How to create module-wide variables in Python?
是否有方法在模块内设置全局变量?当我尝试用下面显示的最明显的方法进行时,python解释器说变量
1 2 3 4 5 6 7 8 9 | ... __DBNAME__ = None def initDB(name): if not __DBNAME__: __DBNAME__ = name else: raise RuntimeError("Database name has already been set.") ... |
在将模块导入到其他文件后
1 2 3 4 | ... import mymodule mymodule.initDB('mydb.sqlite') ... |
追溯到:
有什么想法吗?我正试着用一个模块来建立一个单体模型,按照这个家伙的建议。
这是发生的事情。
首先,Python真正拥有的全局变量是模块范围的变量。不能生成真正全局的变量;您所能做的只是在特定范围内生成一个变量。(如果在python解释器中生成一个变量,然后导入其他模块,那么您的变量在最外部的范围内,因此在python会话中是全局的。)
要使模块成为全局变量,只需将其分配给一个名称。
设想一个名为foo.py的文件,其中包含以下单行:
1 | X = 1 |
现在假设您导入它。
1 2 | import foo print(foo.X) # prints 1 |
然而,让我们假设您希望使用模块范围变量之一作为函数内部的全局变量,如您的示例中所示。python的默认设置是假定函数变量是本地的。在尝试使用global之前,只需在函数中添加一个
1 2 3 4 5 6 | 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.") |
顺便说一下,对于这个例子,简单的
最后,正如本页中其他人所指出的,两个前导下划线向Python发出信号,表示您希望该变量对模块"私有"。如果您使用
在python中,最好的做法是不执行
编辑:如果出于某种原因,您需要在没有
在函数中,全局变量名将是只读的;您将无法重新绑定实际的全局变量名。(如果在函数内分配给该变量名,它只会影响函数内的局部变量名。)但可以使用该局部变量名访问实际的全局对象,并在其中存储数据。
您可以使用
1 2 3 4 5 | __DBNAME__ = [None] # use length-1 list as a mutable # later, in code: if __DBNAME__[0] is None: __DBNAME__[0] = name |
一个
1 2 3 4 5 6 7 8 9 | 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 |
(实际上不需要将数据库名称变量大写。)
我喜欢使用
使用
通过在模块上显式访问模块级变量来显式访问它们
简而言之:这里描述的技术与Steveha的答案相同,只是没有创建任何人工助手对象来显式地限定变量的范围。相反,模块对象本身被赋予一个变量指针,因此在从任何地方访问时都提供显式范围。(类似于本地函数范围中的赋值)。
把它想象成当前模块的自我,而不是当前实例!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 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)) |
由于模块是缓存的,因此只能导入一次,因此您可以在任意多个客户机上导入
1 2 3 4 | # client_a.py import db db.initialize_db('mongo') |
1 2 3 4 5 | # client_b.py import db if (db.db_name == 'mongo'): db.db_name = None # this is the preferred way of usage, as it updates the value for all clients, because they access the same reference from the same module object |
1 2 3 4 5 6 7 8 | # client_c.py from db import db_name # be careful when importing like this, as a new reference"db_name" will # be created in the module namespace of client_c, which points to the value # that"db.db_name" has at import time of"client_c". if (db_name == 'mongo'): # checking is fine if"db.db_name" doesn't change db_name = None # be careful, because this only assigns the reference client_c.db_name to a new value, but leaves db.db_name pointing to its current value. |
作为一个额外的奖励,我发现它总体上很像Python,因为它很好地符合Python的政策,显式比隐式要好。
史蒂文的回答对我很有帮助,但忽略了一个重要的问题(我认为威斯蒂正在讨论这个问题)。如果只访问但不在函数中分配变量,则不需要使用global关键字。
如果不使用global关键字分配变量,那么python将创建一个新的局部变量——模块变量的值现在将隐藏在函数中。使用global关键字在函数内分配模块var。
pylint 1.3.1在python 2.7下,如果不分配var,则强制不使用global。
1 2 3 4 5 6 7 8 9 | module_var = '/dev/hello' def readonly_access(): connect(module_var) def readwrite_access(): global module_var module_var = '/dev/hello2' connect(module_var) |
为此,需要将变量声明为全局变量。但是,也可以使用
1 | global __DBNAME__ |
你爱上了一个微妙的怪癖。不能在python函数内重新分配模块级变量。我认为这是为了阻止人们意外地在函数内部重新分配东西。
您可以访问模块名称空间,只是不应该尝试重新分配。如果您的函数分配了一些东西,它会自动成为一个函数变量——而python不会在模块名称空间中查找。
你可以做到:
1 2 3 4 5 6 7 | __DB_NAME__ = None def func(): if __DB_NAME__: connect(__DB_NAME__) else: connect(Default_value) |
但不能在函数内部重新分配
一个解决办法:
1 2 3 4 5 6 7 | __DB_NAME__ = [None] def func(): if __DB_NAME__[0]: connect(__DB_NAME__[0]) else: __DB_NAME__[0] = Default_value |
注意,我不是重新分配