python-3.x - 在 Python 3 中从同一包内和包外导入模块

标签 python-3.x import package

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

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

现在,这些是我的条件:
  • mod2需要导入mod1。
  • interface.py 和 mod2 都需要作为主脚本独立运行。如果您愿意,可以将 interface 视为实际程序,将 mod2 视为包的内部测试器。

  • 因此,在 Python 2 中,我只需执行 import mod1在 mod2.py 和 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'
    同样,如果我使用相对导入: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 问题:
  • Python -- import the package in a module that is inside the same package
  • How to do relative imports in Python?
  • Absolute import module in same package

  • 相关链接:
  • https://docs.python.org/3.5/tutorial/modules.html
  • https://www.python.org/dev/peps/pep-0328/
  • https://www.python.org/dev/peps/pep-0366/
  • 最佳答案

    TLDR:

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


  • The only "solution", I've found is to go up one folder and do python -m pkg.mod2 and then it works.



    使用 -m switch 确实是“唯一”的解决方案——它之前已经是唯一的解决方案。旧的行为只是完全靠运气才能奏效。它甚至可以在不修改您的代码的情况下被破坏。

    去“一个文件夹”只是将你的包添加到搜索路径中。安装包或修改搜索路径也可以。详情见下文。

    But do we have to be adding the package prefix pkg to every import to other modules within that package?



    您必须引用您的包 - 否则您想要哪个模块是不明确的。包引用可以是绝对的或相对的。

    相对导入通常是您想要的。它节省了写作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>将您的导入绑定(bind)到不同的名称。例如,import pkg.mod2 as mod2让您只使用模块名称。

    Even more, to run any scripts inside the package, do I have to remember to go one folder up and use the -m switch? That's the only way to go??



    如果您的软件包安装正确,您可以使用 -m从任何地方切换。例如,您始终可以使用 python3 -m json.tool .
    echo '{"json":"obj"}' | python -m json.tool
    

    如果你的包没有安装(还),你可以设置 PYTHONPATH 到它的基本目录。这包括搜索路径中的包,并允许 -m切换以正确找到它。

    如果你在可执行文件的目录下,你可以执行export PYTHONPATH="$(pwd)/.."快速挂载要导入的包。

    I'm confused. This scenario was pretty straightforward with python 2, but looks awkward in python 3.



    这种情况在 python 2 中基本上被打破了。虽然在许多情况下它很简单,但在任何其他情况下很难或完全不可能修复。

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

    关于python-3.x - 在 Python 3 中从同一包内和包外导入模块,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47319423/

    相关文章:

    javascript - 如何定义相对于某个根目录的 typescript 导入路径(使用 webpack)?

    c++ - 是否有用于 Debian/Ubuntu 的 Boost 1.5.3 软件包?

    python - 找出用于安装当前包的 Python?

    python-3.x - Homebrew python@3.8更新后重新安装python包

    python - 如何在 wsgi 应用程序中使用 gzip 编码?

    javascript - React-Native 导入库并在多个组件中可用

    javascript - 如何找到 rollup 3.1.0 更新错误?

    python-3.x - OpenCv的circle函数可以用来画奇数直径的圆吗?

    python - 如何获取 Python 中所有内置函数的列表

    java - Eclipse - 数组无法解析