相对python导入的最终答案 [英] Ultimate answer to relative python imports
问题描述
我知道Python中存在很多关于相同导入问题的问题,但似乎没有人设法提供正确使用的明确示例。
I know that there are lots of questions about the same import issues in Python but it seems that nobody managed to provide a clear example of correct usage.
让我们说我们有一个包 mypackage
,包含两个模块 foo
和 bar
。在 foo
里面我们需要能够访问 bar
。
Let's say that we have a package mypackage
with two modules foo
and bar
. Inside foo
we need to be able to access bar
.
因为我们还在开发它, mypackage
不在 sys.path
中。
Because we are still developing it, mypackage
is not in sys.path
.
我们希望能够:
- import
mypackage.foo
- 运行
foo.py
作为脚本并执行示例用法或测试__ main __
部分。 - 使用Python 2.5
- import
mypackage.foo
- run
foo.py
as a script and execute the sample usage or tests from the__main__
section. - use Python 2.5
我们如何在foo.py中进行导入,以确保它在所有这些情况下都能正常工作。
How do we have to do the import in foo.py in order to be sure it will work in all these cases.
# mypackage/__init__.py
...
# mypackage/foo/__init__.py
...
# mypackage/bar.py
def doBar()
print("doBar")
# mypackage/foo/foo.py
import bar # fails with module not found
import .bar #fails due to ValueError: Attempted relative import in non-package
def doFoo():
print(doBar())
if __name__ == '__main__':
doFoo()
推荐答案
查看 PEP 328 :
相对导入使用模块的
__ name __
属性,用于确定模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为'__ main __'
),则解析相对导入,就像模块是顶级模块一样,无论模块实际位于文件系统上的位置。
Relative imports use a module's
__name__
attribute to determine that module's position in the package hierarchy. If the module's name does not contain any package information (e.g. it is set to'__main__'
) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.
当你运行 foo.py $ c时$ c>作为脚本,该模块的
__ name __
是'__ main __'
,因此您无法进行相对导入。即使 mypackage
在 sys.path
上,也是如此。基本上,如果导入该模块,您只能从模块进行相对导入。
When you run foo.py
as a script, that module's __name__
is '__main__'
, so you cannot do relative imports. This would be true even if mypackage
was on sys.path
. Basically, you can only do relative imports from a module if that module was imported.
以下是解决此问题的几个选项:
Here are a couple of options for working around this:
1)在 foo.py
中,检查 __ name__ =='__ main __'
和有条件地将 mypackage
添加到 sys.path
:
1) In foo.py
, check if __name__ == '__main__'
and conditionally add mypackage
to sys.path
:
if __name__ == '__main__':
import os, sys
# get an absolute path to the directory that contains mypackage
foo_dir = os.path.dirname(os.path.join(os.getcwd(), __file__))
sys.path.append(os.path.normpath(os.path.join(foo_dir, '..', '..')))
from mypackage import bar
else:
from .. import bar
2)始终从mypackage导入栏使用导入
bar
,然后执行 foo .py
以这种方式自动显示 mypackage
:
2) Always import bar
using from mypackage import bar
, and execute foo.py
in such a way that mypackage
is visible automatically:
$ cd <path containing mypackage>
$ python -m mypackage.foo.foo
这篇关于相对python导入的最终答案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!