如何在 Python 模块中正确使用相对或绝对导入?
在 Python 中使用相对导入有一个缺点:您将无法再作为独立运行模块,因为您将收到异常:
ValueError:尝试在非包中进行相对导入
代码
# /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)的解决方案。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您可以以一种不同的方式开始“以独立方式运行模块”:
而不是:
使用:
当然,
foo/__init__.py
文件必须存在。另请注意,
foo.py
和bar.py
之间存在循环依赖关系 - 这是行不通的。我想这只是你的例子中的一个错误。看来将其用作 foo/bar.py 的第一行也非常有效:
然后您可以直接在 POSIX 系统。
You could just start 'to run the modules as standalones' in a bit a different way:
Instead of:
Use:
Of course, the
foo/__init__.py
file must be present.Please also note, that you have a circular dependency between
foo.py
andbar.py
– this won't work. I guess it is just a mistake in your example.It seems it also works perfectly well to use this as the first line of the
foo/bar.py
:Then you can execute the script directly in POSIX systems.
首先,我假设您意识到您所写的内容会导致循环导入问题,因为 foo 导入 bar ,反之亦然;尝试添加
到 test.py,你会发现它失败了。该示例必须更改才能工作。
因此,您所要求的实际上是在相对导入失败时回退到绝对导入;事实上,如果您将 foo.py 或 bar.py 作为主模块执行,其他模块将位于根级别,并且它们是否与系统上的另一个模块共享名称,将选择哪个模块取决于sys.path 中的顺序。由于当前目录通常是第一个,因此如果可用,将选择本地模块 - 即,如果当前工作目录中有一个“os.py”文件,则将选择该文件而不是内置模块。
一个可能的建议是:
foo.py
bar.py:
顺便说一句,从正确的位置调用脚本通常会更好。
可能是最好的方法。此将模块作为脚本运行。
First, I assume you realize what you've written would lead to a circular import issue, because foo imports bar and viceversa; try adding
to test.py, and you'll see it fails. The example must be changed in order to work.
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.
A possibile suggestion is:
foo.py
bar.py:
By the way calling scripts from the proper position is usually way better.
Is probably the best way to go. This runs the module as a script.
放弃相对导入:无论如何,你应该将你的包命名空间视为全局命名空间。
使这个变得可口的技巧是适当地编辑
sys.path
。这里有一些值得思考的地方:Ditch relative imports: you should think of your package namespace as a global one, anyway.
The trick to making this palatable is editing
sys.path
appropriately. Here is some food for thought:每个文件夹中都需要
__init__.py
。相对导入仅在您执行以下操作时才有效:
test.py导入foo.py并且foo.py可以相对导入文件夹中的任何内容>test.py 及以上。
你做不到:
它永远不会起作用。
您可以尝试 sys.path.append 或 sys.path.insert 解决方案,但您会搞砸路径,并且 f= 会出现问题打开(文件名)。
You need
__init__.py
in each folder.Relative import works only when you do:
test.py imports foo.py and foo.py can relative import anything from the folder of test.py and above.
You can't do:
It will never work.
You can try the sys.path.append or sys.path.insert solution, but you are going to screw up the paths and you'll have problems with the f=open(filename).
只需将“main”放在不同的 .py 文件中即可。
Just put the "main" in a different .py file.
到目前为止,我发现的唯一解决方案是根本不使用相对导入。
由于当前的限制,我想知道什么时候应该有人在 Python 中使用相对导入。
在我使用的所有配置中,
sys.path
包含当前目录作为第一个参数,因此只需使用import foo
而不是from 。 import foo
,因为它会做同样的事情。So far the only solution I found was not to use relative imports at all.
Due to current limitations, I'm wondering when someone is supposed to use relative imports in Python.
On all configurations that I used the
sys.path
contained the current directory as the first argument, so just useimport foo
instead offrom . import foo
, because it will do the same.