Python 2.5 中的相对导入

问题描述 投票:0回答:2

我知道 Python 中存在很多关于相同导入问题的问题,但似乎没有人能够提供正确用法的清晰示例。

假设我们有一个包

mypackage
,其中包含两个模块
foo
bar
。在
foo
内部,我们需要能够访问
bar

因为我们还在开发中,所以

mypackage
不在
sys.path
中。

我们希望能够:

  • 导入
    mypackage.foo
  • foo.py
    作为脚本运行,并执行
    __main__
    部分中的示例用法或测试。
  • 使用Python 2.5

我们如何在 foo.py 中进行导入,以确保它在所有这些情况下都能工作。

# 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()
python import relative-path python-2.5
2个回答
32
投票

查看来自PEP 328的以下信息:

相对导入使用模块的

__name__
属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,将其设置为
'__main__'
),则将解析相对导入,就像该模块是顶级模块一样,无论该模块实际位于文件系统上的位置。

当您将

foo.py
作为脚本运行时,该模块的
__name__
'__main__'
,因此您无法进行相对导入。即使
mypackage
位于
sys.path
上也是如此。基本上,如果导入了某个模块,则只能从该模块进行相对导入。

以下是解决此问题的几个选项:

1) 在

foo.py
中,检查是否
__name__ == '__main__'
并有条件地将
mypackage
添加到
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) 始终使用

bar
导入
from mypackage import bar
,并以
foo.py
自动可见的方式执行
mypackage

$ cd <path containing mypackage>
$ python -m mypackage.foo.foo

7
投票

我的解决方案看起来更干净一些,并且可以与所有其他导入一起放在顶部:

try:
   from foo import FooClass
except ModuleNotFoundError:
   from .foo import FooClass
© www.soinside.com 2019 - 2024. All rights reserved.