Python子模块内部引用——它们真的是疯狂的吗?

3 投票
3 回答
6029 浏览
提问于 2025-04-16 02:22

抱歉提前问了个新手问题。我有点搞不懂这个,文档也没帮上忙!

考虑一下下面这个文件夹结构:

spam.py
foo     / __init__.py
          ham.py
          eggs.py

还有以下这段代码:

# __init__.py
# blank

# ham.py
print( "got ham!" )

# eggs.py
print( "got eggs, importing ham!" )
import foo.ham

现在,如果我在 spam.py 里面使用 import foo.eggs,一切都正常,所有模块的引用都能正常工作。

但是

如果我直接执行 eggs.py,我就会遇到一个错误:ImportError: No module named foo.ham!如果我把 foo.ham 的引用改成只用 ham,那就能正常工作了……但这样我就不能 import foo.eggs 了!

那么,我该怎么开发 eggs 呢?如果我用不带点的引用,开发是没问题的,但我无法尝试,因为我不能 import 这个模块!如果我用完整的 foo.ham 引用,我可以导入这个包,但又无法执行子模块进行开发!

这是Python的打包结构出了问题吗?我是不是做错了什么?

3 个回答

0

这是Python的打包结构。通常,一个模块可以通过点号引用从当前目录导入其他模块,也可以从$PYTHONPATH目录导入。你需要明白,模块的引用其实就是指向这个模块的相对路径。所以说,解释器无法导入在文件系统中找不到的模块。

1

要让foo这个文件正常工作,它的上级目录必须在Python的搜索路径里:

$ ls foo
eggs.py  ham.py  ham.pyc  __init__.py  __init__.pyc
$ python foo/ham.py
got ham!
$ python foo/eggs.py
got eggs, importing ham!
Traceback (most recent call last):
  File "foo/eggs.py", line 2, in <module>
    import foo.ham
ImportError: No module named foo.ham
$ PYTHONPATH=. python foo/eggs.py
got eggs, importing ham!
got ham!
1

这看起来是可行的:下面是目录结构:

~/test/kl% ls -R
.:
foo  spam.py

./foo:
eggs.py  eggs.pyc  ham.py  ham.pyc  __init__.py  __init__.pyc

这里是文件内容:

~/test/kl% cat spam.py 
import foo.eggs

~/test/kl% cd foo/
~/test/kl/foo% cat eggs.py
print( "got eggs, importing ham!" )
import ham

我们可以从 spam.py 和 foo/eggs.py 中导入 ham:

~/test/kl% python spam.py 
got eggs, importing ham!
got ham!

一个有用的规则是,当你输入 python script.py 时,包含 script.py 的目录会被加到 sys.path 的最前面,sys.path 是用来查找模块的目录列表。这就是为什么 python spam.py 可以正常工作,而不需要改变 PYTHONPATH 的原因。

~/test/kl% python foo/eggs.py
got eggs, importing ham!
got ham!

在这里,~/test/kl/foo 被添加到了 sys.path 中。这没问题,因为 eggs.py 试图 import ham。由于 ham.py~/test/kl/foo 中,而这个目录在 sys.path 里,所以 Python 能顺利找到它。

~/test/kl% cd foo
~/test/kl/foo% python eggs.py
got eggs, importing ham!
got ham!

目录 ~/test/kl 并不在我的 PYTHONPATH 中。

撰写回答