同一包中的绝对导入模块

14 投票
4 回答
13495 浏览
提问于 2025-04-18 05:47

我把我的导入问题简化成了一个简单的基本案例。假设我有一个Python包:

mypkg/
   __init__.py
   a.py
   b.py

a.py文件里包含:

def echo(msg):
    return msg

b.py文件里包含:

from mypkg import a       # possibility 1, doesn't work
#import a                 # possibility 2, works
#from mypkg.a import echo  # import also fails

print(a.echo())

当我运行 python b.py 时,在Python 2.7.6和Python 3.3.5上都会出现 ImportError: No module named mypkg 的错误。我也尝试在这两种情况下都加上 from __future__ import absolute_import,结果还是一样的问题。

预期结果:

我希望可能性1能正常工作。

我为什么想这样做:

可能性2就不太理想了。假设标准库可能会引入一个叫 a 的包(虽然这种情况不太可能,但你明白我的意思)。在Python 2中,它会先搜索当前包,而Python 3及以上版本则做了绝对导入的修改,会先检查标准库。无论我有什么理由,可能性1应该是能工作的,对吧?我敢肯定我以前做过成千上万次。

注意:如果你在 mypkg 外部写一个脚本, from mypkg import a 是没有问题的。

我的问题类似于python - 同目录下模块的绝对导入,但作者暗示我现在的做法应该是可以工作的。

4 个回答

-1

试试这个:

import sys
import os
this_dir = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.dirname(this_dir))

from mypkg import a
print(a.echo())
0

我觉得问题出在你在 mypkg 文件夹里没有对 mypkg 的引用。看看当我尝试运行你的例子时,Python 是怎么做的(使用详细模式):

# trying /vagrant/mypkg/mypkg.py

这就是为什么它能找到这个模块,因为它并不存在。你可以用一个小技巧,就是创建一个叫 mypkg.py 的文件,里面写上这一行:

import a

但这其实只是你上面提到的第二种可能性换了个形式。如果不知道你想要实现什么,我会选择 包内引用 文本中的第一个例子。我会这样写 b.py

from a import echo

print(echo('message'))
2

是的,这样是行不通的,因为当你调用 print(mypkg.a.echo()) 时,mypkg 还在加载中(mypkg.__init__ -> mypkg.b)。这是因为Python会先加载父模块。你可以查看这个链接了解更多:https://docs.python.org/3/reference/import.html#searching

你可以把 print(mypkg.a.echo()) 放到一个函数里:

def echo():
   mypkg.a.echo()

然后:

import mypkg.b
mypkg.b.echo()

或者甚至:

print(sys.modules['mypkg.a'].echo())

另外,你也可以帮助Python找到你的模块:

import importlib
mypkg.a = importlib.import_module('mypkg.a')
mypkg.a.echo()
22

使用from mypkg import a是正确的写法。不要在Python包的目录里面直接运行脚本,这样会让同一个模块用不同的名字出现,可能会导致错误。应该在包含mypkg的目录下运行python -m mypkg.b

如果想要在任何目录下都能运行,mypkg需要放在pythonpath里面。

撰写回答