19

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

假设我们有一个mypackage包含两个模块foobar. 在里面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()
4

2 回答 2

32

查看PEP 328中的以下信息:

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

当您foo.py作为脚本运行时,该模块__name__'__main__',因此您不能进行相对导入。即使mypackage是 on也是如此sys.path。基本上,如果该模块已导入,您只能从该模块执行相对导入。

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

1) 在foo.py中,检查是否__name__ == '__main__'并有条件地添加mypackagesys.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
于 2011-11-28T18:15:05.783 回答
7

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

try:
   from foo import FooClass
except ModuleNotFoundError:
   from .foo import FooClass
于 2017-08-03T15:38:51.900 回答