【问题标题】:Import a module from a directory (package) one level up从上一级目录(包)导入模块
【发布时间】:2015-12-22 09:52:34
【问题描述】:

在 Python 中从上一级目录导入模块的正确方法是什么?该目录是一个包含所有这些模块的 Python 包,我有一个包含需要这些模块的代码的子目录。

以下工作正常,但这只是一个 hack。我想要一个推荐的/pythonic的方式。

import sys
sys.path.append("../")
from fruit import Fruit
print("OK")

目录结构:

pkg1
   __init__.py  
   fruit.py  
   +sub_pkg
      __init__.py
      recipe.py

fruit.py 的内容

class Fruit:
   def get_name(self):
       print("Fruit name")

sub_pkg/recipe.py 的内容.. 只是一个导入行:

from fruit import Fruit

当我跑步时:

python recipe.py

它给出了以下错误。

Traceback (most recent call last):
  File "recipe.py", line 2, in <module>
    from fruit import Fruit
ImportError: No module named fruit

我也试过了:from pkg1.fruit import Fruit,不行。还看了其他类似的问题.. python -m recipe.pypython -m sub_pkg/recipe.py 不起作用。

【问题讨论】:

  • 这个答案怎么样:stackoverflow.com/questions/72852/…
  • from pkg1.fruit import Fruit 遇到的错误是什么?
  • @Irit: ImportError: No module named temp.fruit
  • 您应该将 pkg1 添加到您的 PYTHONPATH。
  • 如果你在正确的地方安装你的python包,你应该不需要从一个目录中导入。一般来说,上层导入不是一个好主意,它表明程序设计不好。设置系统路径然后像往常一样导入是比下面提到的相对导入更好的解决方案,后者在 python3 上中断。

标签: python


【解决方案1】:

如果您遇到问题,也可以使用以下方法。

从当前目录导入

from . import something

从上面的一个目录导入

from .. import fruit

相对路径文档:https://docs.python.org/2/tutorial/modules.html#intra-package-references

RELATIVE PACKAGE ISSUE ValueError: Attempted relative import in non-package

适用于对相关软件包有疑问的人。这是您的解决方案。

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name"

还有解释,抄自另一个python docs

当主模块由其文件名指定时,package 属性将设置为 None 。为了在直接执行模块时允许相对导入,在第一个相对导入语句之前需要类似于以下的样板:

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name

请注意,仅当顶层包已经可以通过 sys.path 访问时,此样板文件才足够。需要额外的代码来操作 sys.path 以便直接执行工作,而无需导入顶级包。

创建包的文档 我不打算粘贴内容,因为它很长,但这里是关于创建包的 python 文档部分。 https://docs.python.org/2/tutorial/modules.html#packages

PYTHONPATH 上的另一个文档 https://docs.python.org/2/using/cmdline.html#envvar-PYTHONPATH

【讨论】:

  • 几乎同时!!
  • 谢谢.. 如果我做任何这些,它会导致 ValueError: Attempted relative import in non-package 。这与 Olexander 在另一个问题中指出的错误相同。但是没看懂解决方法!
  • 您参考了文档。这总是更有益的。
  • 在 python3 中不起作用。 SystemError: Parent module '' not loaded, cannot perform relative import
  • 小更正“从上面的一个目录导入”只有当你在一个正确的 python 包中并且上面的目录是一个正确的 python 包时才是正确的。 (即所有东西都有一个 init.py 并且被设计成一个 python 包)。如果您只是想在通用文件系统上提升一级,则需要更改 python 搜索的路径。
【解决方案2】:

你可以使用relative imports:

from ..fruit import Fruit

【讨论】:

    【解决方案3】:

    不要使用上层导入,而是有一个入口点,您可以从最上层调用该入口点,并在 recipe.py 文件中设置相对于该入口点的导入。

    例如:

    pkg1/
       __init__.py  
       main.py
       fruit.py  
       +sub_pkg
          __init__.py
          recipe.py
    

    其中main.py 包含:

    #!/usr/bin/env python3
    
    import subpkg.recipe as recipe
    import fruit
    
    if __package__ is None and __name__ == "__main__":
        __package__ = "main"
        print()
        # Call recipe.py or fruit.py methods from here
    

    recipe.py:

    import fruit
    # do stuff with fruit module, which is properly imported now
    

    要运行,请致电python3 main.py

    【讨论】:

    • 只在脚本中处理包会更有益。而不是创建单独的运行脚本。这消除了在其上运行脚本的可能性,在某些情况下可能无法扩展。
    • @AdriVelaz 地址哪个包在哪个列表中?我需要一些上下文
    • __package__ = "expected.package.name" 在脚本级别使用if __name__ == "__main__": 这里也是文档。 python.org/dev/peps/pep-0366/#proposed-change
    • 完成,但除了 python 的正确性之外,它并没有真正添加任何东西来解决 OP 的问题
    • 在脚本级别它定义了包的上下文。它回答了OP的问题。它在任何正式导入之前完成。
    【解决方案4】:

    在你的主文件recipe.py 中添加pkg1 路径到PYTHONPATH

    sys.path.append('/path/to/pkg1')
    

    或者使用相对路径

    sys.path.append('../..')
    

    这应该允许从程序中的任何位置导入pkg1

    始终可以选择使用此处建议的相对导入,我发现使用绝对导入更具可读性并且不太可能导致错误。此外,在使用相对导入的大型项目中,您会不断计算路径层次结构,而在使用绝对导入时,很容易知道您总是引用一个根目录。

    关于 Python 2.5 中从 PEP328 的相对导入:

    阅读依赖于相对导入的代码也不太清楚,因为读者可能会对打算使用哪个模块感到困惑。 Python 用户很快就学会了不要在他们的包的子模块的名称中重复标准库模块的名称,但是您无法防止您的子模块的名称被用于在 Python 的未来版本中添加的新模块。


    Guido 建议在相对导入中使用前导点以避免如上所述的模棱两可的导入,再次来自 PEP328

    Guido 已宣布相对导入将使用前导点。单个前导点表示相对导入,从当前包开始。两个或多个前导点表示对当前包的父级的相对导入,在第一个点之后每个点一个级别。

    【讨论】:

    • 设置 PYTHONPATH 有效,并且似乎是基于文档的可接受的解决方案(将 pkg 添加到搜索路径)。我已经尝试过 sys.path.append ,但决定不这样做
    • 我已经尝试解决此类问题 5 个多小时了,您的第二个解决方案有效。谢谢!!
    猜你喜欢
    • 1970-01-01
    • 2021-03-15
    • 2015-12-23
    • 1970-01-01
    • 2019-06-19
    • 2022-07-22
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多