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

查看:228
本文介绍了如何在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__测试就足够了,因为除空字符串以外的任何字符串值都将为true,因此任何实际的数据库名称都将为true.但是对于可能包含数字值可能为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

A 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天全站免登陆