Python:设置属于导入模块命名空间的变量

3 投票
2 回答
2276 浏览
提问于 2025-04-18 13:38

假设我有一个模块叫做 params.py,里面声明了一堆变量:

a = 0.2
b = 0.4
...

在使用这个模块的时候,我想用 * 来导入它的命名空间,这样引用起来更方便。但是这样做似乎只能访问到这些参数的值,却不能重新设置它们:

from params import *
def test1():
    print(a)  #this works: printing out the value of params.a

def test2():
    a= 0.5  #doesn't work: does not change the value of params.a 

我尝试用 params.a = 0.5 来引用这个变量,但也不行(出现了 NameError,提示 "params" 没有定义)

我的问题是:用这种方式导入的变量,怎么才能设置或重置它的值呢?

2 个回答

1

好吧,我想到的简单解决办法是对同一个模块使用两个导入语句:

from params import *
import params

第一个语句让我可以直接使用变量的值,而不需要加上 "params." 前缀,第二个语句则让我在需要的时候重新绑定这些变量。

params.a = 0.5

我不知道这样做是否符合最佳实践(可能不符合)。不过就我所见,这个方法是有效的。欢迎其他建议。

编辑:这个方法不行,因为变量 a 的值不会反映更新后的值:

print(a)  #say it prints 0.2
params.a = 0.5
print(a) # will still print 0.2
print(params.a) #will print 0.5

所以这里的教训是,如果你用 from params import a 导入了变量,那么即使原始值发生了变化,你也只能得到当初导入时的值。也就是说,这是按值导入,而不是按引用导入。

3

test2() 函数里把 a = 0.5 赋值,只对这个函数有效,也就是说它是局部的。

你想做的是给模块设置属性。

举个例子:

import params

def test1():
    print(params.a)

def test2():
    params.a = 0.5

详细信息请查看:Python作用域规则的简要说明

注意: 了解Python几乎所有东西都是某种对象,并且通常都有属性,这一点是很有帮助的。这包括模块、类、类的实例、函数等等。

更新:虽然这样做不太推荐,但这确实能“完全”实现你想要的效果:

foo.py:

from params import *  # noqa


def test1():
    print(a)


def test2():
    global a

    a = 0.5

params.py:

a = 1

demo:

$ python -i foo.py
>>> test1()
1
>>> test2()
>>> test1()
0.5
>>>

更新 II: 不过我还要指出,正如我在评论中提到的,这实际上并没有改变 params.a 的引用。请看:

$ python -i foo.py
>>> id(params.a)
140602494749016
>>> id(a)
140602494749016
>>> test1()
1
>>> test2()
>>> test1()
0.5
>>> id(params.a)
140602494749016
>>> id(a)
140602494760472
>>>

总结: 一般来说,请使用这里提供的第一个选项。

撰写回答