是否有方法在模块内部设置全局变量?当我试图用下面所示的最明显的方法来实现它时,Python解释器说变量__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 ...
有什么想法吗?我正试图根据this fellow's建议,通过使用模块来设置单例。
通过在模块上显式访问模块级变量来显式访问模块级变量
简而言之:这里描述的技术与steveha's answer,中描述的技术相同,除了之外,不创建任何人工辅助对象来显式地限定变量的范围。相反,模块对象本身被赋予一个变量指针,因此在从任何地方访问时都提供显式的作用域。(类似于本地函数范围内的赋值)。
把它想象成当前模块而不是当前实例的self!
As modules are cached and therefore import only once,您可以在任意数量的客户机上导入
db.py
,操作相同的通用状态:作为一个额外的奖励,我发现它总体上是相当Python的,因为它很好地符合Python的政策,显式优于隐式。
史蒂夫哈的回答对我很有帮助,但忽略了一个重要的问题(我认为怀斯提正在回答这个问题)。如果只访问但不在函数中分配变量,则不需要全局关键字。
如果在不使用global关键字的情况下分配变量,那么Python将创建一个新的局部变量——模块变量的值现在将隐藏在函数中。使用global关键字在函数中分配模块变量。
Python 2.7下的Pylint 1.3.1如果不分配变量,则强制不使用global
这是发生的事情。
首先,Python真正拥有的唯一全局变量是模块范围的变量。不能生成真正全局的变量;只能在特定范围内生成变量。(如果您在Python解释器中创建一个变量,然后导入其他模块,那么您的变量在Python会话的最外层范围中,因此是全局的。)
创建模块全局变量所需做的只是为名称赋值。
想象一下一个名为foo.py的文件,其中包含这一行:
现在想象一下你导入它。
但是,假设您希望将模块范围变量之一用作函数中的全局变量,如您的示例所示。Python的默认设置是假设函数变量是局部的。您只需在函数中添加一个
global
声明,然后再尝试使用全局。顺便说一下,对于本例,简单的
if not __DBNAME__
测试就足够了,因为除了空字符串之外的任何字符串值都将计算为true,因此任何实际的数据库名称都将计算为true。但是对于可能包含数字值0的变量,不能只说if not variablename
;在这种情况下,应该使用is
运算符显式测试None
。我修改了示例以添加一个显式的None
测试。对None
的显式测试从来没有错,所以我默认使用它。最后,正如其他人在本页中所指出的,前面的两个下划线向Python发出信号,表示您希望变量对模块是“私有的”。如果您做过
import * from mymodule
,Python将不会将带有两个前导下划线的名称导入到您的名称空间中。但是如果你只做一个简单的import mymodule
,然后说dir(mymodule)
,你会看到列表中的“private”变量,如果你显式地引用mymodule.__DBNAME__
,Python不会在意,它只会让你引用它。双前导下划线是模块用户的一个重要线索,您不希望他们将该名称重新绑定到自己的某个值。在Python中,最好不要做
import *
,而是通过使用mymodule.something
或显式地执行类似from mymodule import something
的导入来最小化耦合并最大化显式性。编辑:如果出于某种原因,您需要在没有
global
关键字的非常旧的Python版本中执行类似的操作,那么有一个简单的解决方法。不要直接设置模块全局变量,而是在模块全局级别使用可变类型,并将值存储在其中。在函数中,全局变量名将是只读的;您将无法重新绑定实际的全局变量名。(如果在函数内指定该变量名,则只会影响函数内的局部变量名。)但可以使用该局部变量名访问实际的全局对象,并在其中存储数据。
您可以使用
list
,但您的代码将很难看:A
dict
更好。但最方便的是类实例,您只需使用一个简单的类:(实际上不需要将数据库名称变量大写。)
我喜欢使用
__m.dbname
而不是__m["DBNAME"]
的语法糖;在我看来,这似乎是最方便的解决方案。但是dict
溶液也可以工作。使用
dict
可以使用任何可散列值作为键,但是如果您对作为有效标识符的名称感到满意,则可以使用上面的Box
之类的小类。相关问题 更多 >
编程相关推荐