如何在Python 3中使用绝对导入导入位于其父目录中的包?

5

我有一个像这样的Python包目录:

proj/
  mod_a/
    __init__.py
    x.py
    submod_x/
      __init__.py
      y.py
  mod_b/
    __init__.py
    z.py

使用 x.py:

import submod_x.y

z.py:

import sys, os.path
sys.path.append(os.path.abspath('../'))

import mod_a.x

现在当我运行以下命令时:
$ python2 z.py

我把y.py中的任务完成了。

但是当我运行时:

$ python3 z.py

我得到了一个异常:

Traceback (most recent call last):
File "z.py", line 4, in <module>
  import mod_a.x
File ".../proj/mod_a/x.py", line 1, in <module>
  import submod_x.y
ImportError: No module named 'submod_x'

我想知道Python 2和Python 3在导入包时有什么不同,并且如何在Python 3中使用绝对导入从其父目录导入位于包中的模块?

2个回答

4
感谢用户的帮助。经过仔细阅读 PEP,我现在能够自己回答这个问题了。
首先,有三种类型的导入需要了解:
  1. Absolute imports.

    import sys
    

    Here, "sys" is a module or package name reachable from sys.path($PATH). Python inserts the directory where the script lies to sys.path by default. In other words, if I run python3 mod_b/z.py under proj/, python will insert proj/mod_b/ to sys.path.

  2. Explicit relative imports.

    from ..mod_a import x
    

    Imports a module relative to current module(possibly not current working directory $PWD). The rationale is quite clearly described in python3 doc. And there are some examples from PEP-0328.

    Attention: explicit relative imports must always use from <> import <>.

  3. Implicit relative imports.

    import submod_x.y
    

    In python2, such an import statement will lead to an import relative to current module implicitly. i.e. If I run python2 mod_a/x.py under proj/, the current module is x, and the module submod_x.y relative to x will be correctly imported. The statement from submod_x import y is equivalent to from .submod_x import y as the explicit relative imports mentioned above.

    However, it is obvious that implicit relative imports may be confused with absolute imports, as mentioned in PEP-0328. According to PEP-0404, python3 no longer supports implicit relative imports.

其次,将脚本放在包内运行被视为反模式,正如Guido在一封邮件中所说:email中提到的那样。这种情况下唯一的用例似乎是运行恰好位于模块目录中的脚本,我一直认为这是一个反模式。如果要改变我的想法,你需要说服我这不是反模式。
这可能会导致显式相对导入无法正常工作,如果你打算这样做,请参考上面链接中的帖子获取解决方案。
以下是其他人的帖子,可能会对你有所帮助: Python3中import语句的更改 从相对路径导入模块

0

我认为你应该在x.py中这样做:

import mod_a.submod_x.y

从文件位置进行的绝对导入使用绝对模块名称或以下方式完成:

from . import submod_x.y

如果proj在sys.path上或者Lib/site-packages包含一个名为proj.pth的文件,其中包含proj的绝对路径,则第一种选项将起作用。我选择后者,因为它允许我在多个site-packages中“安装”我的所有Python项目目录,而无需复制。 - Terry Jan Reedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接