IPython中的导入是如何工作的

12 投票
1 回答
16144 浏览
提问于 2025-04-18 17:07

我对IPython中的导入语句是怎么回事有点困惑。我在网上搜索了很多,但没有找到相关的信息。

在Python 2中,隐式相对导入是可以用的,但我不知道在Python 3的IPython中是不是也这样。

使用点语法的相对导入似乎根本无法工作:

In [6]: ls 
dsp/  __init__.py  __init__.pyc  utils/

In [7]: from .utils import capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-e7d50007bdd1> in <module>()
----> 1 from .utils import capture

ValueError: Attempted relative import in non-package

导入使用点语法的模块似乎是不可能的:

In [8]: cd utils
/home/user/workspace/mypkg/mypkg/utils

In [9]: ls
capture/  capture.py  capture.pyc  cext/  __init__.py  __init__.pyc

In [10]: from capture import Capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-10-8c31c76d052d> in <module>()
----> 1 from capture import Capture

/home/user/workspace/mypkg/mypkg/utils/capture.py in <module>()
     17 import tarfile
     18 import re
---> 19 from .. import utils
     20 from . import flprint
     21 from select import poll

ValueError: Attempted relative import in non-package

有没有什么简明的文档可以参考一下?

1 个回答

10

问题在于,我从包的层级结构中较低的位置导入了模块,而这个位置和模块的导入语句使用的位置不一致。所以如果我进入utils目录并运行

from capture import Capture

那么capture就成了层级结构的顶层。在capture模块中的导入语句

from .. import utils

就超出了顶层。Python不知道“..”指的是什么,因为模块并不知道自己属于哪个包。如果我再回到mypkg目录,我会遇到同样的问题

In [13]: cd ..
/home/user/workspace/myproj/mypkg

In [14]: from utils import capture
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-14-c87f26b2171d> in <module>()
----> 1 from utils import capture

/home/user/workspace/myproj/mypkg/utils/capture.py in <module>()
    18 import re
    19 import zmq
---> 20 from .. import utils
    21 from . import flprint
    22 from select import poll

ValueError: Attempted relative import beyond toplevel package

在这种情况下,utils是顶层,所以

from . import flprint

可以正常工作,但

from .. import utils

就不行了。

我需要再向上移动一个目录:

In [19]: cd ..
/home/user/workspace/myproj

In [20]: from mypkg.utils import capture

In [21]: cap = capture.Capture

IPython可以导入当前工作目录中的包和模块,或者从导入路径中的目录导入。我可以把包添加到导入路径中,这样就可以从任何工作目录导入。

In [23]: import sys

In [24]: sys.path.append('/home/user/workspace/myproj')

In [25]: cd
/home/user

In [26]: from mypkg.utils import capture

你可以使用 sys.path.append 让你的模块“自我意识”,但是正如 alpha_989 指出的那样,这可能会导致名称冲突。不过,这在从交互式终端会话中处理包层级结构时是一个有用的解决方法。

撰写回答