如何在Python模块中正确使用相对或绝对导入?

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

在 Python 中使用相对导入有一个缺点,你将无法再以独立方式运行模块,因为你会得到一个异常:

ValueError: Attempted relative import in non-package

# /test.py: just a sample file importing foo module
import foo
...

# /foo/foo.py:
from . import bar
...
if __name__ == "__main__":
   pass

# /foo/bar.py: a submodule of foo, used by foo.py
from . import foo
...
if __name__ == "__main__":
   pass

我应该如何修改示例代码才能执行所有:

test.py
foo.py
bar.py

我正在寻找适用于 python 2.6+(包括 3.x)的解决方案。

python module package python-module python-import
6个回答
22
投票

您可以以一种不同的方式开始“独立运行模块”:

代替:

python foo/bar.py

用途:

python -mfoo.bar

当然,

foo/__init__.py
文件必须存在。

另请注意,

foo.py
bar.py
之间存在循环依赖 – 这是行不通的。我想这只是你的例子中的一个错误。

更新:看起来使用它作为

foo/bar.py
的第一行也非常有效:

#!/usr/bin/python -mfoo.bar

然后就可以直接在POSIX系统中执行脚本了。


16
投票

首先,我假设您意识到您所写的内容会导致循环导入问题,因为 foo 导入 bar ,反之亦然;尝试添加

from foo import bar

到 test.py,你会看到它失败了。该示例必须更改才能工作。

因此,您所要求的实际上是当相对导入失败时回退到绝对导入;事实上,如果您将 foo.py 或 bar.py 作为主模块执行,其他模块将位于根级别,并且它们是否与系统上的另一个模块共享名称,将选择哪个模块取决于sys.path 中的顺序。由于当前目录通常是第一个,因此如果可用,将选择本地模块 - 即,如果当前工作目录中有一个“os.py”文件,则将选择它而不是内置模块。

一个可能的建议是:

foo.py

try:
    from . import bar
except ValueError:
    import bar

if __name__ == "__main__":
    pass

bar.py:

if __name__ == "__main__":
    pass

顺便说一句,从正确的位置调用脚本通常会更好。 python -m foo.bar

可能是最好的方法。这
将模块作为脚本运行


1
投票

使其变得可口的技巧是适当地编辑

sys.path

。这里有一些值得深思的地方:


# 上一级目录 _root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) 暂时 sys.path.insert(0, _root_dir)



1
投票
__init__.py


相对导入仅在您执行以下操作时才有效:

python test.py

test.py 导入 foo.py 并且 foo.py 可以相对导入 test.py 及以上文件夹中的任何内容。

你不能这样做:

cd foo python foo.py python bar.py

它永远不会起作用。

您可以尝试 sys.path.append 或 sys.path.insert 解决方案,但您会搞砸路径,并且 f=open(filename) 会遇到问题。


0
投票


-2
投票

由于当前的限制,我想知道什么时候有人应该在 python 中使用相对导入。

在我使用的所有配置中,

sys.path

包含当前目录作为第一个参数,因此只需使用

import foo
而不是
from . import foo
,因为它会执行相同的操作。
    

© www.soinside.com 2019 - 2024. All rights reserved.