如何在 Python 中创建模块范围的变量? [英] How to create module-wide variables in Python?

查看:23
本文介绍了如何在 Python 中创建模块范围的变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有办法在模块内部设置全局变量?当我尝试以如下所示的最明显的方式执行此操作时,Python 解释器说变量 __DBNAME__ 不存在.

Is there a way to set up a global variable inside of a module? When I tried to do it the most obvious way as appears below, the Python interpreter said the variable __DBNAME__ did not exist.

...
__DBNAME__ = None

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

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

And after importing the module in a different file

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

回溯是:

...UnboundLocalError:在赋值之前引用了局部变量DBNAME"...

... UnboundLocalError: local variable 'DBNAME' referenced before assignment ...

有什么想法吗?我正在尝试使用模块来设置单例,根据 这个家伙的推荐.

Any ideas? I'm trying to set up a singleton by using a module, as per this fellow's recommendation.

推荐答案

这是正在发生的事情.

首先,Python 真正拥有的唯一全局变量是模块范围的变量.你不能创建一个真正全局的变量;您所能做的就是在特定范围内创建一个变量.(如果你在 Python 解释器中创建一个变量,然后导入其他模块,你的变量在最外层的范围内,因此在你的 Python 会话中是全局的.)

First, the only global variables Python really has are module-scoped variables. You cannot make a variable that is truly global; all you can do is make a variable in a particular scope. (If you make a variable inside the Python interpreter, and then import other modules, your variable is in the outermost scope and thus global within your Python session.)

创建模块全局变量所需要做的只是分配一个名称.

All you have to do to make a module-global variable is just assign to a name.

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

Imagine a file called foo.py, containing this single line:

X = 1

现在想象你导入它.

import foo
print(foo.X)  # prints 1

但是,假设您想将模块范围的变量之一用作函数内部的全局变量,如您的示例所示.Python 的默认设置是假设函数变量是本地的.在尝试使用全局之前,您只需在函数中添加一个 global 声明.

However, let's suppose you want to use one of your module-scope variables as a global inside a function, as in your example. Python's default is to assume that function variables are local. You simply add a global declaration in your function, before you try to use the 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__ 测试就足够了,因为除空字符串之外的任何字符串值都将评估为真,因此任何实际的数据库名称都将评估为真.但是对于可能包含可能为 0 的数值的变量,您不能只说 if not variablename;在这种情况下,您应该使用 is 运算符显式测试 None.我修改了示例以添加显式 None 测试.None 的显式测试永远不会出错,所以我默认使用它.

By the way, for this example, the simple if not __DBNAME__ test is adequate, because any string value other than an empty string will evaluate true, so any actual database name will evaluate true. But for variables that might contain a number value that might be 0, you can't just say if not variablename; in that case, you should explicitly test for None using the is operator. I modified the example to add an explicit None test. The explicit test for None is never wrong, so I default to using it.

最后,正如其他人在此页面上指出的那样,两个前导下划线向 Python 发出信号,表明您希望该变量对模块是私有的".如果您曾经执行过 import * from mymodule,Python 不会将带有两个前导下划线的名称导入到您的命名空间中.但是如果你只是做一个简单的 import mymodule 然后说 dir(mymodule) 你会在列表中看到私有"变量,如果你明确引用 mymodule.__DBNAME__ Python 不会在意,它只会让你引用它.双前导下划线是您模块用户的主要线索,您不希望他们将该名称重新绑定到他们自己的某个值.

Finally, as others have noted on this page, two leading underscores signals to Python that you want the variable to be "private" to the module. If you ever do an import * from mymodule, Python will not import names with two leading underscores into your name space. But if you just do a simple import mymodule and then say dir(mymodule) you will see the "private" variables in the list, and if you explicitly refer to mymodule.__DBNAME__ Python won't care, it will just let you refer to it. The double leading underscores are a major clue to users of your module that you don't want them rebinding that name to some value of their own.

Python 中的最佳实践被认为是不执行 import *,而是通过使用 mymodule.something 或显式执行导入来最小化耦合并最大化显式性比如from mymodule import something.

It is considered best practice in Python not to do import *, but to minimize the coupling and maximize explicitness by either using mymodule.something or by explicitly doing an import like from mymodule import something.

如果出于某种原因,您需要在没有 global 关键字的非常旧的 Python 版本中执行类似的操作,有一个简单的解决方法.不要直接设置模块全局变量,而是在模块全局级别使用可变类型,并将您的值存储在其中.

If, for some reason, you need to do something like this in a very old version of Python that doesn't have the global keyword, there is an easy workaround. Instead of setting a module global variable directly, use a mutable type at the module global level, and store your values inside it.

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

In your functions, the global variable name will be read-only; you won't be able to rebind the actual global variable name. (If you assign to that variable name inside your function it will only affect the local variable name inside the function.) But you can use that local variable name to access the actual global object, and store data inside it.

你可以使用 list 但你的代码会很丑:

You can use a list but your code will be ugly:

__DBNAME__ = [None] # use length-1 list as a mutable

# later, in code:  
if __DBNAME__[0] is None:
    __DBNAME__[0] = name

dict 更好.但最方便的是类实例,你可以只使用一个平凡的类:

A dict is better. But the most convenient is a class instance, and you can just use a trivial class:

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

(您实际上不需要将数据库名称变量大写.)

(You don't really need to capitalize the database name variable.)

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

I like the syntactic sugar of just using __m.dbname rather than __m["DBNAME"]; it seems the most convenient solution in my opinion. But the dict solution works fine also.

使用 dict,您可以使用任何可散列的值作为键,但是当您对作为有效标识符的名称感到满意时,您可以使用像 Box 这样的普通类在上面.

With a dict you can use any hashable value as a key, but when you are happy with names that are valid identifiers, you can use a trivial class like Box in the above.

这篇关于如何在 Python 中创建模块范围的变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆