用于相对进口的python包装


71

首先,很抱歉,我知道相对进口存在很多疑问,但我没有找到解决办法。如果可能的话,我想使用以下目录布局:

myClass/
    __init__.py
    test/
        demo.py
        benchmark.py
        specs.py
    src/
        __init__.py
        myClass.py

现在我的问题是:

  • 包中的测试文件如何正确导入myClass.py?

  • 假设您将myClass作为libs / myClass或include / myClass中的子模块,则如何从外部导入包?

到目前为止,我找不到适合的解决方案。据我了解Guido的决定,应该可以这样做,from ..src import myClass但这会出错:

ValueError: Attempted relative import in non-package

看起来没有将myClass视为包。阅读文档

__init__.py文件是使Python将目录视为包含包的必需文件。

似乎我缺少指定软件包脚本位置的内容,我应该使用.pth吗?


6
@布伦特·纽维(Brent Newey),是的,相对的进口似乎是一个持续不断的话题,在阅读了很多答案之后,我仍然感到迫切需要具体描述我的情况。在显示此q之后,在#python IRC频道上,很多人建议使用平面目录结构:“很多人抵制Python希望使用目录和文件来获取语义名称空间信息的方式。最好是屈服并执行Python想要什么。” jcalderone.livejournal.com/39794.html
eerne 2010年

8
有人能提供示例目录布局或遵循某些约定的一些实际软件包的链接吗?(最好是在github上)
eerne 2010年

1
有没有__init__.pytest目录中?ValueError: Attempted relative import in non-package可能与此有关。
jfs 2010年


阅读官方文档对我有很大帮助!docs.python.org/3/reference/...
Kavin拉朱小号

Answers:


42

ValueError: Attempted relative import in non-package

表示您尝试在非包模块中使用相对导入。它的问题与具有此from ... import语句的文件有关,而不与您尝试导入的文件有关。

因此,例如,如果要在测试中进行相对导入,则应使测试成为软件包的一部分。这表示

  1. 加入__init__.py测试/
  2. 从外部脚本运行它们,例如鼻子测试

如果您以as的身份运行某些东西python myClass/test/demo.py,则相对导入也将无法正常工作,因为您以不是以包形式运行演示模块。相对导入要求使用它们的模块本身以软件包模块from myClass.test.demo import blabla或相对导入的形式导入。


28

经过数小时的搜索,昨晚我在python中找到了相对导入的答案!或至少是一个简单的解决方案。解决此问题的最佳方法是从另一个模块调用模块。所以说你想demo.py导入myClass.py。在myClass子软件包根目录下的文件夹中,他们需要有一个调用其他两个文件的文件。从我收集的工作目录中,始终会考虑到该目录,__main__因此,如果您demo.py使用demo.py脚本测试导入,您将收到该错误。为了显示:

文件夹层次结构:

myClass/
    main.py #arbitrary name, can be anything
    test/
        __init__.py
        demo.py
    src/
        __init__.py
        myClass.py

myClass.py:

def randomMaths(x):
    a = x * 2
    y = x * a
    return y

demo.py:

from ..src import myClass

def printer():
    print(myClass.randomMaths(42))

main.py:

import test.demo

demo.printer()

如果您demo.py在解释器中运行,则会生成错误,但main.py不会运行。这有点令人费解,但它有效:D


3
我正在使用Python 2.7,并且通过做三件事只能使上面的代码工作。首先,在main.py所在的级别上,添加了一个__init__.py。其次,我将demo.printer()更改为test.demo.printer()。第三,我在main.py上方更改了目录并运行python -m myClass.main。否则,这对我来说是一个非常有用的答案。:)
Paul

0

包内引用描述了如何myClasstest/*。要从外部导入软件包,您应该PYTHONPATH在运行导入程序之前将其路径添加到环境变量,或者sys.path在导入之前在代码中列出。

为什么会from ..src import myClass失败:可能src不是python包,您无法从那里导入。您应该如上所述将其添加到python路径。


相对导入始终进行。许多软件包中都有较小的子软件包,并且依赖于相对进口。OP不会询问如何引用外部程序包。他在问如何引用一个包中的另一个子包。
cstrutton
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.