跨模块变量
从这里我得到了一个关于如何使用其他模块中的变量的想法。这一切在
import foo as bar
中都能正常工作。
但是我不想把我的模块导入为“bar”,我想直接使用它,而不加任何前缀,比如
from foo import *
这样的话,就无法修改其他模块中的变量。读取是可以的!有没有什么想法或建议呢?
4 个回答
使用 import foo from bar
的时候,你不是把 bar
当作一个变量来引入,而是把它当作一个常量来引入。
简短回答:不可以,这不可能,你必须使用前缀。
要明白的是,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
这样,每个模块都会得到 x
和 y
的本地副本。修改 x
不会在其他模块中看到,而你也看不到其他模块的修改 :-(
如果想要修改一个变量的中心副本,你必须导入整个模块:import foo
,然后修改 foo.x
。这样只有一个副本存在,大家都在访问它 :-)
[链接的问题也提到可以把共享变量放在模块 builtin 中。不要这样做!这样虽然可以省去读取时的前缀,但写的时候还是需要前缀,而且这非常不推荐。]
为Python辩护
如果你对需要使用 foo.
前缀感到不满,那么你可能也会对访问对象变量时需要使用 self.
前缀感到不满。总的来说,这就是Python的工作方式——因为你不需要声明变量,所以只能使用前缀。
但这也有好处:在阅读Python代码时,你很容易看到每个变量的位置。在我看来,这非常好。
支持证据:在其他语言如C++/Java中,很多人会在所有对象变量名上使用 m_
前缀,以达到类似的效果……
风格建议
你不需要
import foo as bar
,直接使用import foo
就可以了。
as
形式并没有带来什么新东西,只是重命名,这会让人困惑。
只有在 "foo" 是一个非常长的名字时才有用;一个特别常见的情况是当 "foo" 在某个包的深处时,这样你可以写import long.package.foo as foo
。from foo import *
在程序中被认为是非常糟糕的风格,因为:阅读你代码的人不知道名字是从哪里来的。
这会污染你的命名空间,可能导致不同模块的名字冲突,从而引发微妙的错误。
显式的形式
from foo import x, y
是可以的,但如果你使用了很多模块中的名字,就会开始出现同样的问题。
在这种情况下,最好使用import foo
,然后明确写出foo.x
和foo.y
。
总之:当不确定时,简单的 import foo
是最好的选择。
例外:在交互式解释器中使用 import *
是非常方便的。不过要注意,它与 reload()
不兼容,所以在调试更改代码时不要使用它。(要调试你正在编写的模块,最好在模块的命名空间内启动一个新的解释器——python -i mymodule.py
/ 在IDLE中按F5。)
据我所知,没办法从一个模块中导入一个值,并让这个值在导入的地方既能读又能写。当你在Python中使用 import foo
时,它会创建一个名为 foo
的模块对象。对这个模块对象的属性进行获取和设置,会改变模块内部的内容。但是当你使用 from foo import something
时,foo
被导入并创建了一个模块对象,但这个对象并不会被返回。相反,Python会把你指定的值从 foo
中复制出来,放到本地作用域里。如果你导入的是像 int
或 str
这样的不可变类型,那么你改变它后,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风格的方法来解决你的问题。