提问人:Akronix 提问时间:11/16/2017 最后编辑:Akronix 更新时间:2/16/2023 访问量:11594
在 Python 3 中,从同一包内和包外导入模块
Import a module from both within same package and from outside the package in Python 3
问:
好的,场景非常简单。我有这个文件结构:
.
├── interface.py
├── pkg
│ ├── __init__.py
│ ├── mod1.py
│ ├── mod2.py
现在,这些是我的条件:
- mod2 需要导入 mod1。
- interface.py 和 mod2 都需要作为主脚本独立运行。如果需要,可以将 interface 视为实际程序,将 mod2 视为软件包的内部测试器。
因此,在 Python 2 中,我将简单地在 mod2.py 内部执行,并且两者都会按预期工作。import mod1
python2 mod2.py
python2 interface.py
但是,这是我不太了解的部分,使用 Python 3.5.2,如果我这样做的话;然后我可以做,但抛出::(import mod1
python3 mod2.py
python3 interface.py
ImportError: No module named 'mod1'
因此,显然,python 3 建议用于避免与内置模块的冲突。好的,如果我使用它,我可以做到;但后来我不能,因为:import pkg.mod1
python3 interface.py
python3 mod2.py
ImportError: No module named 'pkg'
同样,如果我使用相对导入:则有效;但 mod2.py 说:( :(from . import mod1
python3 interface.py
SystemError: Parent module '' not loaded, cannot perform relative import
我发现的唯一“解决方案”是上一个文件夹并做,然后它就可以工作了。但是,我们是否必须将包前缀添加到该包中的其他模块的每次导入中?更重要的是,要运行包中的任何脚本,我是否必须记得转到一个文件夹并使用 -m 开关?这是唯一的出路??python -m pkg.mod2
pkg
我很困惑。这种情况在 python 2 中非常简单,但在 python 3 中看起来很尴尬。
更新:我已经上传了这些文件,其中包含(上面称为“解决方案”)工作源代码:https://gitlab.com/Akronix/test_python3_packages。请注意,我仍然不喜欢它,并且看起来比 python2 解决方案丑陋得多。
我已经读过的相关 SO 问题:
相关链接:
答:
顶级域名:
- 使用 运行代码。
python -m pkg.mod2
- 使用 导入代码。
from . import mod1
我发现的唯一“解决方案”是上一个文件夹并做,然后它就可以工作了。
python -m pkg.mod2
使用交换机确实是“唯一”的解决方案 - 它之前已经是唯一的解决方案。旧的行为只是纯粹出于运气;它甚至可能在不修改代码的情况下被破坏。-m
“向上一个文件夹”只是将您的包添加到搜索路径中。安装软件包或修改搜索路径也有效。有关详细信息,请参见下文。
但是,我们是否必须将包前缀 pkg 添加到该包中其他模块的每次导入中?
你必须有一个对你的包的引用 - 否则你想要哪个模块是模棱两可的。包引用可以是绝对引用,也可以是相对引用。
相对导入通常是您想要的。它显式地节省了编写,使重构和移动模块变得更加容易。pkg
# inside mod1.py
# import mod2 - this is wrong! It can pull in an arbitrary mod2 module
# these are correct, they uniquely identify the module
import pkg.mod2
from pkg import mod2
from . import mod2
from .mod2 import foo # if pkg.mod2.foo exists
请注意,您始终可以使用将导入绑定到其他名称。例如,允许您仅使用模块名称。<import> as <name>
import pkg.mod2 as mod2
更重要的是,要运行包中的任何脚本,我是否必须记得转到一个文件夹并使用 -m 开关?这是唯一的出路??
如果您的软件包安装正确,您可以从任何地方使用交换机。例如,您始终可以使用 .-m
python3 -m json.tool
echo '{"json":"obj"}' | python -m json.tool
如果尚未安装包,则可以将 PYTHONPATH
设置为其基目录。这包括搜索路径中的包,并允许交换机正确找到它。-m
如果您位于可执行文件的目录中,则可以执行以快速装载要导入的包。export PYTHONPATH="$(pwd)/.."
我很困惑。这种情况在 python 2 中非常简单,但在 python 3 中看起来很尴尬。
这种情况在 python 2 中基本被打破了。虽然它在许多情况下很简单,但在任何其他情况下都很难或完全不可能解决。
在简单的情况下,新行为更加笨拙,但在任何情况下都是健壮可靠的。
评论
我也有类似的问题。 我解决了它,添加了
import sys sys.path.insert(0,".package_name")
添加到包文件夹中的文件中。__init__.py
评论
from pkg.mod1 import fun
from .mod1 import fun
from . import mod1