在Python 3

时间:2017-11-16 00:07:38

标签: python-3.x import package

好的,这个场景非常简单。我有这个文件结构:

.
├── interface.py
├── pkg
│   ├── __init__.py
│   ├── mod1.py
│   ├── mod2.py

现在,这些是我的条件:

  • mod2需要导入mod1。
  • interface.py和mod2都需要作为主脚本独立运行。如果需要,可以将接口视为实际程序,将mod2视为软件包的内部测试程序。

因此,在Python 2中,我只需在mod2.py中执行import mod1python2 mod2.pypython2 interface.py都可以按预期工作。

然而,如果我做import mod1,这是我不太了解的部分,使用Python 3.5.2;然后我可以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'

同样,如果我使用相对导入: from . import mod1然后python3 interface.py有效;但mod2.py说SystemError: Parent module '' not loaded, cannot perform relative import :( :(

唯一的“解决方案”,我发现是上一个文件夹并执行python -m pkg.mod2然后它可以工作。但是,我们是否必须将包前缀pkg添加到该包中其他模块的每个导入中?更重要的是,要在包中运行任何脚本,我是否必须记得去一个文件夹并使用-m开关?那是唯一的出路吗?

我很困惑。这个场景在python 2中非常简单,但在python 3中看起来很尴尬。

更新:我上传了这些文件(上面称为“解决方案”)工作源代码:https://gitlab.com/Akronix/test_python3_packages。请注意,我仍然不喜欢它,看起来比python2解决方案更加丑陋。

我已经读过的相关SO问题:

相关链接:

1 个答案:

答案 0 :(得分:2)

TLDR:

  • 使用python -m pkg.mod2运行代码。
  • 使用from . import mod1
  • 导入代码
  

唯一的“解决方案”,我发现是上一个文件夹并执行python -m pkg.mod2,然后就可以了。

使用-m开关确实是“唯一”解决方案 - 它已经是以前唯一的解决方案了。旧的行为只是纯粹的运气;它甚至可以在不修改代码的情况下被破坏。

“一个文件夹”只是将您的包添加到搜索路径中。安装包或修改搜索路径也可以。有关详细信息,请参阅下文。

  

但我们是否必须将包前缀pkg添加到该包中其他模块的每次导入?

您必须拥有对您的包的引用 - 否则您需要的模块不明确。包引用可以是绝对的也可以是相对的。

相对导入通常是您想要的。它明确地节省了写作pkg,使重构和移动模块变得更容易。

# mod1.py
# import mod2 - this is wrong! It can pull in an arbitrary mod2 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中基本上是已经。虽然在很多情况下它很简单,但在任何其他情况下修复都很困难或完全不可能。

在简单的情况下,新行为更加尴尬,但无论如何都是健壮可靠的。