跨模块变量

1 投票
4 回答
2068 浏览
提问于 2025-04-15 17:44

这里我得到了一个关于如何使用其他模块中的变量的想法。这一切在

import foo as bar

中都能正常工作。

但是我不想把我的模块导入为“bar”,我想直接使用它,而不加任何前缀,比如

from foo import *

这样的话,就无法修改其他模块中的变量。读取是可以的!有没有什么想法或建议呢?

4 个回答

0

使用 import foo from bar 的时候,你不是把 bar 当作一个变量来引入,而是把它当作一个常量来引入。

3

简短回答:不可以,这不可能,你必须使用前缀。

要明白的是,from foo import x, y 是在把 x 复制到你的命名空间里。这相当于:

import foo
# COPY TO YOUR NAMESPACE
x = foo.x
y = foo.y
# `from foo import` does NOT leave `foo` in your namespace
def foo

这样,每个模块都会得到 xy 的本地副本。修改 x 不会在其他模块中看到,而你也看不到其他模块的修改 :-(

如果想要修改一个变量的中心副本,你必须导入整个模块:import foo,然后修改 foo.x。这样只有一个副本存在,大家都在访问它 :-)

[链接的问题也提到可以把共享变量放在模块 builtin 中。不要这样做!这样虽然可以省去读取时的前缀,但写的时候还是需要前缀,而且这非常不推荐。]

为Python辩护

如果你对需要使用 foo. 前缀感到不满,那么你可能也会对访问对象变量时需要使用 self. 前缀感到不满。总的来说,这就是Python的工作方式——因为你不需要声明变量,所以只能使用前缀。

但这也有好处:在阅读Python代码时,你很容易看到每个变量的位置。在我看来,这非常好。

支持证据:在其他语言如C++/Java中,很多人会在所有对象变量名上使用 m_ 前缀,以达到类似的效果……

风格建议

  1. 你不需要 import foo as bar,直接使用 import foo 就可以了。
    as 形式并没有带来什么新东西,只是重命名,这会让人困惑。
    只有在 "foo" 是一个非常长的名字时才有用;一个特别常见的情况是当 "foo" 在某个包的深处时,这样你可以写 import long.package.foo as foo

  2. from foo import * 在程序中被认为是非常糟糕的风格,因为:

    • 阅读你代码的人不知道名字是从哪里来的。

    • 这会污染你的命名空间,可能导致不同模块的名字冲突,从而引发微妙的错误。

    显式的形式 from foo import x, y 是可以的,但如果你使用了很多模块中的名字,就会开始出现同样的问题。
    在这种情况下,最好使用 import foo,然后明确写出 foo.xfoo.y

总之:当不确定时,简单的 import foo 是最好的选择。

例外:在交互式解释器中使用 import * 是非常方便的。不过要注意,它与 reload() 不兼容,所以在调试更改代码时不要使用它。(要调试你正在编写的模块,最好在模块的命名空间内启动一个新的解释器——python -i mymodule.py / 在IDLE中按F5。)

2

据我所知,没办法从一个模块中导入一个值,并让这个值在导入的地方既能读又能写。当你在Python中使用 import foo 时,它会创建一个名为 foo 的模块对象。对这个模块对象的属性进行获取和设置,会改变模块内部的内容。但是当你使用 from foo import something 时,foo 被导入并创建了一个模块对象,但这个对象并不会被返回。相反,Python会把你指定的值从 foo 中复制出来,放到本地作用域里。如果你导入的是像 intstr 这样的不可变类型,那么你改变它后,foo 模块里的内容是不会反映出来的。这就像这样:

>>> class N(object):
...   def __init__(self, value):
...     self.value = value
>>> n = N(3)
>>> value = n.value
>>> print value, n.value
3 3
>>> value = 4
>>> print value, n.value
4 3

除了那些粗糙的黑客手段,如果你真的想修改模块里的变量,你需要直接导入整个模块,然后在模块上修改变量。但通常来说,这样做说明设计得不太好。如果你是 foo 模块的作者,可能需要考虑一些其他更符合Python风格的方法来解决你的问题。

撰写回答