Python:为什么导入的模块无法引用另一个导入的模块?
main.py:
import subone
import subtwo
subone.py:
a = 'abc'
subtwo.py:
print subone.a
运行 python main.py
时出现了一个错误:NameError: name 'subone' is not defined
。我本来期待它能打印出 'abc'。
我尝试用 from
import
和类来重构代码,但还是没用:
main.py:
from subone import * # Only using from X import * for example purposes.
from subtwo import *
print 'from main.py:', a.out
subone.py:
class A:
out = 'def'
a = A()
subtwo.py:
# This throws NameError: name 'a' is not defined
print a.out
# This throws NameError: name 'A' is not defined
b = A()
print b.out
但是它会打印出 'from main.py: def'。 (用 import
也能正常工作。)
为什么会这样呢?看起来一旦 subone
被导入,它应该可以在 subtwo
中使用。
这是因为直接让导入的模块相互依赖而不通过它们的“父”模块是不好的编程习惯吗?有没有其他标准的方法来处理这个问题?
更新:
我现在明白了,第一个例子之所以不工作,是因为 print subone.a
这一行无法识别 subone
这个名字,因为它不在 subtwo
's 命名空间中(尽管它在 main.py
中),而且它是在 subtwo
模块内被调用的。可以通过在 subtwo.py
的顶部使用 import subone
来解决这个问题——这不会重新加载模块,但会将其添加到 subtwo
的命名空间中,这样 subtwo
就可以使用它了。
但是这样的话:
main.py:
from subone import Nugget
from subtwo import Wrap
wrap = Wrap()
print wrap.nugget.gold
subone.py:
class Nugget:
gold = 'def'
subtwo.py:
class Wrap:
nugget = Nugget()
我本以为因为 Wrap
和 Nugget
都直接加载到 main
的命名空间中,它们可以互相引用,但却出现了 NameError: name 'Nugget' is not defined
的错误。难道是因为 Wrap
是在 subtwo 的命名空间内被检查/评估的,而不是直接在 main
的命名空间中?
5 个回答
如果你不把 subone
导入到 subtwo
这个命名空间里,subtwo
就会完全是空的。
从编程的角度来看,如果你想的话,subone
和 subtwo
可以互相依赖,但你需要明确地把它们连接起来(通过 import
)。
你能解释一下为什么你觉得subone应该对subtwo可用吗?因为subone是由main导入的。实际上,subtwo.py可以在不知道main.py导入了什么的情况下被编译。
另外,如果有第二个程序导入了subtwo.py,subtwo对subone的了解应该依赖于哪个main程序在导入subtwo吗?这样会降低subtwo的可重用性。
看起来你在想编译是一个有顺序的过程,像是在积累状态信息:先编译main.py,然后在这个过程中编译/import subone.py,积累来自它的信息,接着再编译/import subtwo.py,使用我们已经积累的信息。
其实,每个模块的编译是独立的,除非声明了依赖关系。这样做让代码的重用和维护变得更简单:隐藏的依赖关系更少。
是不是因为让导入的模块相互依赖而不通过它们的“父”模块是糟糕的编程?
并不是这样……只是让模块2依赖于模块1而不说明这一点是糟糕的编程,也就是说,模块2应该声明“我依赖于模块1”。
如果你这样修改了你的 subtwo.py,那么它就能正常工作了。
import subone
print subone.a
当你在 subtwo.py 中使用 subone.a 时,你是在尝试访问 subtwo.py 中的 subone 名称空间,而在这个名称空间中,应该有一个属性 "a"。
当你在 subtwo.py 中写 import subone 时,subone 就被添加到了名称空间中,并且 subone 名称空间里有属性 a,所以 subone.a 就能正常使用了。
我还建议你使用 dir() 来看看名称空间是如何被添加的。
在 subtwo.py 中,你可以这样做:
print dir()
import subone
print dir()
print subone.a
同样,试着在你的 import 语句前后加上 "print dir()",这样你就能更清楚地理解这个概念了。
"import x" 会把 'x' 添加到当前模块的名称空间,而 "from x import *" 则会把所有模块级别的属性直接添加到当前模块的名称空间中。
所以在你之前提到的 main.py、subone.py 和 subtwo.py 的例子中,main.py 的名称空间会包含 'subone' 和 'subtwo',而 subtwo.py 的名称空间是空的,无法访问 subone.a。
[编辑:更多解释]
考虑以下文件:
main.pyprint "Before importing subone : ", dir()
import subone
print "After importing subone and before importing subtwo: ", dir()
import subtwo
print "After importing subone and subtwo: ", dir()
subone.py
a = 'abc'
subtwo.py
print dir()
import subone
print "module level print: ", subone.a
print dir()
def printX():
print subone.a
以及运行 main.py 的输出:
Before importing subone : ['__builtins__', '__doc__', '__file__', '__name__', '__package__']
After importing subone and before importing subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
module level print: abc
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone']
After importing subone and subtwo: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'subone', 'subtwo']
一些观察结果
- 你会注意到,当导入模块 subtwo.py 时,打印语句会立即执行。
- 所以当在 main.py 中导入 subone 和 subtwo 时,main.py 的名称空间会被扩展。
- 这并不意味着 subtwo 的名称空间会被扩展,因此 "a" 只能通过 subone.a 在 main.py 中使用。
- 当我们在 subtwo.py 中写 import subone 时,subtwo 的名称空间就会被 subone 扩展,subone 模块的属性 a 也可以通过 subone.a 在 subtwo.py 中使用。