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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3616952/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 11:58:02  来源:igfitidea点击:

How to properly use relative or absolute imports in Python modules?

pythonmodulepackagespython-modulepython-import

提问by sorin

Usage of relative imports in Python has one drawback, you will not be able to run the modules as standalones anymore because you will get an exception: ValueError: Attempted relative import in non-package

在 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

How should I modify the sample code in order to be able to execute all: test.py, foo.pyand bar.py

我应该如何修改示例代码以便能够执行 all: test.pyfoo.py以及bar.py

I'm looking for a solution that works with python 2.6+ (including 3.x).

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

采纳答案by Alan Franzoni

First, I assume you realize what you've written would lead to a circular import issue, because foo imports bar and viceversa; try adding

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

from foo import bar

to test.py, and you'll see it fails. The example must be changed in order to work.

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

So, what you're asking is really to fallback to absolute import when relative import fails; in fact, if you're executing foo.py or bar.py as the main module, the other modules will just lie at the root level, and if they share the name with another module on the system which one will be picked depends on the order in sys.path. Since the current dir is usually the first, local modules will be picked if available - i.e., if you've got an 'os.py' file in the current working dir, it'll be picked instead of the builtin one.

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

A possibile suggestion is:

一个可能的建议是:

foo.py

文件

try:
    from . import bar
except ValueError:
    import bar

if __name__ == "__main__":
    pass

bar.py:

酒吧.py:

if __name__ == "__main__":
    pass

By the way calling scripts from the proper position is usually waybetter.

通过从适当位置调用脚本的方式是通常的方式更好。

python -m foo.bar

Is probably the best way to go. This runs the module as a script.

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

回答by bogdan

So far the only solution I found was not to use relative imports at all.

到目前为止,我发现的唯一解决方案是根本不使用相对导入。

Due to current limitation, I'm wondering when someone is supposed to use relative imports in python.

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

On all configurations that I used the sys.pathcontained the current directory as first argument so just use import fooinstead of from . import foobecause it will do the same.

在我使用sys.path包含的当前目录作为第一个参数的所有配置中,只使用import foo而不是from . import foo因为它会做同样的事情。

回答by Jacek Konieczny

You could just start 'to run the modules as standalones' in a bit a different way:

您可以以不同的方式开始“将模块作为独立运行”:

Instead of:

代替:

python foo/bar.py

Use:

用:

python -mfoo.bar

Of course, the foo/__init__.pyfile must be present.

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

Please also note, that you have a circular dependency between foo.pyand bar.py– this won't work. I guess it is just a mistake in your example.

另请注意,您在foo.py和之间存在循环依赖bar.py- 这将不起作用。我想这只是你的例子中的一个错误。

Update: it seems it also works perfectly well to use this as the first line of the foo/bar.py:

更新:似乎也可以很好地使用它作为以下内容的第一行foo/bar.py

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

Then you can execute the script directly in POSIX systems.

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

回答by Nathan Davis

Why not just put the "main" in a different .py file?

为什么不将“main”放在不同的 .py 文件中?

回答by Edward Z. Yang

Ditch relative imports: you should think of your package namespace as a global one, anyway.

放弃相对导入:无论如何,您应该将包命名空间视为全局命名空间。

The trick to making this palatable is editing sys.pathappropriately. Here is some food for thought:

使这变得可口的诀窍是sys.path适当地编辑。这里有一些值得思考的食物:

# one directory up
_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.insert(0, _root_dir)for now

回答by Dimitris D

You need __init__.pyin each folder.

您需要__init__.py在每个文件夹中。

Relative import works only when you do:

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

python test.py

test.py imports foo.py and foo.py can relative import anything from the folder of test.py and above.

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

You can't do:

你不能这样做:

cd foo
python foo.py
python bar.py

It will never work.

它永远不会奏效。

You can try the sys.path.append or sys.path.insert solution but you gonna screw up the paths and you'll have problems with the f=open(filename).

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