【问题标题】:Python imports when scripts are run from different folder (ancestor)从不同文件夹(祖先)运行脚本时的 Python 导入
【发布时间】:2020-08-24 01:42:31
【问题描述】:

我有一个具有一些固定结构的大型存储库,并且我通过一些文件夹和 python 脚本对其进行了扩展,以便为其整体添加额外的功能。结构如下:

  • 顶级文件夹
    • 功能A
      • someModuleA.py
      • __ 初始化 __.py
    • 功能 B
      • someModuleB.py
      • __ 初始化 __.py
    • 应用
    • __ 初始化 __.py
    • app.py

现在someModuleA.pysomeModuleB.py 可以通过app.py 调用,但同时也可以直接调用,但是这个调用必须来自顶层文件夹才能正确解析文件中的相对路径,即通过python ./featureA/someModuleA.py

这一切都很好,但现在我需要来自someModuleB 的一些函数定义在someModuleA 中,因此我想导入这个模块。我已经尝试过绝对和相对导入,但都失败了不同的错误,绝对导入与

from toplevelfolder.featureA import someModuleA as A

# ModuleNotFoundError: No module named 'toplevelfolder'

和相对导入

from toplevelfolder.featureA import someModuleA as A

# ImportError: attempted relative import with no known parent package

现在我可以看到,当从toplevelfolder 调用python 时,相对导入会导致问题,因为.. 将代表后者的父目录,而不是featureA 的父目录。但是,我无法掌握第一条错误消息,特别是因为toplevelfolder 不应该是一个模块,而是一个包。

如果可能不修改 PYTHONPATH 或 sys.path 或类似的东西,是否有另一种我不知道的在 Python 中导入的方法?

【问题讨论】:

  • 我建议将您的代码称为可执行模块,例如:path/to/pythonX.Y -m toplevelfolder.app 而不是path/to/pythonX.Y toplevelfolder/app.py
  • @sinoroc 不能解决问题,我更感兴趣的是在顶层文件夹中运行 someModuleA 而不是 app
  • 它是否被称为appfoobar 都无关紧要。当然,您总是必须根据您自己的特定用例调整此处给出的答案。无论如何...如果您确保始终使用绝对导入,那么它应该可以工作。这是假设顶级包和模块确实在当前工作目录中或安装在 site packages 中。
  • 粘贴到你的导入上方:` ``` import os,sys,inspect currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) parentdir = os.path.dirname(currentdir) sys.path.insert(0,parentdir) ```
  • 不要乱用sys.path,你应该试着把你的项目变成一个可安装的包:packaging.python.org/tutorials/packaging-projects

标签: python python-import python-module python-packaging


【解决方案1】:

尝试将其粘贴到您的导入上方:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

那么您应该可以从父文件夹导入文件。

【讨论】:

    【解决方案2】:

    不是 100% 确定这里的目标是什么。我的建议是:

    1. 清楚地确定您想要的顶级模块和包是什么。

    2. 使所有导入都是绝对的。

    3. 要么:

      • 使您的项目成为真正的可安装项目,以便将那些顶级模块和包安装在环境的site-packages 目录中;
      • 或确保当前工作目录是包含顶级模块和包的目录。
    4. 确保通过可执行模块或包方法而不是脚本方法调用你的代码,如果“入口点”想要执行是 package

      的一部分
      • DO(可执行模块或包):
        • path/to/pythonX.Y -m toplevelpackage.module
        • path/to/pythonX.Y -m toplevelpackage.subpackage(假设有一个toplevelpackage/subpackage/__main__.py 文件)
      • 不要(脚本在包中):
        • path/to/pythonX.Y toplevelpackage/module.py
    5. (可选) 稍后,一旦一切正常并且一切都在控制之中,您可能会决定将部分或全部导入更改为相对。 (如果事情做对了,我相信可以做到这一点,以便可以从目录结构中的任何级别调用可执行模块作为当前工作目录。)

    参考资料:

    【讨论】:

      【解决方案3】:

      不要包含顶级目录。在 featureB.someModuleB 中:

      from featureA.someModuleA import two
      

      Sample directory.

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-17
        • 1970-01-01
        • 2014-09-03
        相关资源
        最近更新 更多