如何从子包内实现绝对导入?

6 投票
1 回答
1361 浏览
提问于 2025-04-18 15:04

我对包中的导入有些困惑。想象一下,我有以下的文件夹结构:

pack
├── __init__.py
├── sub1
│   ├── __init__.py
│   └── mod1.py
└── sub2
    ├── __init__.py
    └── mod2.py

在mod1.py文件里,我有以下代码来导入mod2.py:

# mod1.py
import pack.sub2.mod2
pack.sub2.mod2.helloworld()

我在包含pack的目录下有一个main.py文件,它导入了pack/sub1/mod1.py。

那么,mod1.py是怎么访问到pack的呢?因为pack并不在mod1.py的同一个目录下。Python会自动把最上层的包添加到sys.path里吗?

1 个回答

3

你可以通过在交互式解释器中查看 sys.path 来了解这个问题。你会发现它的第一个元素是解释器被告知要运行的脚本的位置。这意味着,当你在顶层(也就是 pack 包的位置)运行你的脚本时,这个位置会自动添加到 sys.path 中。这和实际的包结构没有关系,所以如果你直接运行 mod1.py 脚本,可能会导致一些问题(这可能就是你把脚本放在顶层的原因!)。

需要注意的是,在 Python 2 中,还有一个隐式相对导入的问题,这虽然和你问的问题没有直接关系,但如果涉及到更多模块时可能会出现。如果你把 mod3.py 加到 sub1 中,你可以在 mod1 中直接用 import mod3 来导入,前缀 pack.sub1 会自动处理。这个隐式行为通常被认为是不好的,在 Python 3 中是不允许的(在 Python 2 中你也可以通过 from __future__ import absolute_import 来禁用它)。如果你想从 pack.sub1.mod1 导入 pack.sub1.mod3,你需要完整地写出名字,或者使用显式的相对导入:from . import mod3

回到你的问题,如果你想避免依赖 packsys.path 中(或者更实际地说,保护 pack 名称的变化),你可以把从 mod1 导入 mod2 的方式改成显式的相对导入。只需使用 from .. import sub2.mod2

撰写回答