Python中的import关键字是如何工作的?

4 投票
4 回答
7444 浏览
提问于 2025-04-16 00:17

假设我有三个文件:

a.py

from d import d

class a:
    def type(self):
        return "a"
    def test(self):
        try:
            x = b()
        except:
            print "EXCEPT IN A"
            from b import b
            x = b()
        return x.type()

b.py

import sys

class b:
    def __init__(self):
        if "a" not in sys.modules:
            print "Importing a!"
            from a import a
        pass
    def type(self):
        return "b"
    def test(self):
        for modules in sys.modules:
            print modules
        x = a()
        return x.type()

c.py

from b import b
import sys

x = b()
print x.test()

然后我运行 python c.py

结果Python报错说:

NameError: global name 'a' is not defined

但是,a确实在 sys.modules 里:

copy_reg
sre_compile
locale
_sre
functools
encodings
site
__builtin__
operator
__main__
types
encodings.encodings
abc
errno
encodings.codecs
sre_constants
re
_abcoll
ntpath
_codecs
nt
_warnings
genericpath
stat
zipimport
encodings.__builtin__
warnings
UserDict
encodings.cp1252
sys
a
codecs
os.path
_functools
_locale
b
d
signal
linecache
encodings.aliases
exceptions
sre_parse
os

我可以修改 b.py 让它变成:

x = a()
改成
x = sys.modules["a"].a()

这样Python就能顺利运行了。

这引出了几个问题:

为什么Python会说它不知道 a 是什么,尽管它在 sys.modules 里?
使用 sys.modules 访问类和函数定义算是“正确”的方式吗?
导入模块的“正确”方式是什么?
比如说
from module import x
或者
import module

4 个回答

1

在你的情况中,a已经在sys.modules里了……但是sys.modules里的所有东西并不都在b的作用范围内。如果你想用re这个模块,你也得把它导入进来。

有时候条件导入是可以接受的,但这次不适合。首先,a和b之间的循环依赖是个麻烦事,应该尽量避免(在Fowler的重构书里有很多解决这种问题的方法)。不过在这里其实没有必要使用条件导入。

b应该直接导入a。你为什么不直接在文件顶部导入它呢?

2

根据Python的文档

导入语句的执行分为两个步骤:(1) 找到一个模块,并在必要时初始化它;(2) 在本地命名空间(也就是导入语句出现的范围)中定义一个或多个名称。

所以问题在于,虽然模块a已经被导入,但名称a只在b.__init__方法的范围内被绑定,而不是在整个b.py文件的范围内。因此在b.test方法中,没有名称a,所以你会遇到NameError错误。

你可能想看看这篇关于导入Python模块的文章,它能帮助你理解使用import时的最佳实践。

3

我想这可能是作用域的问题。如果你在构造函数里导入一个模块,那么你只能在这个构造函数里使用它,也就是在导入语句之后才能用。

撰写回答