理解Python中的一系列进口

dim*_*414 3 python import python-3.x

我知道有几个类似的问题,但我很难理解我得到的错误,浏览文档和类似的问题还没有帮助.如果有的话,类似的问题让我觉得我正在做的是对的.

我有以下文件:

SRC/main.py

from pack import pack

if __name__ == '__main__':
    pack.exec("Hello Universe!")
Run Code Online (Sandbox Code Playgroud)

SRC /包/ pack.py

import util

def exec(text):
    util.write(text)

if __name__ == '__main__':
    exec("Hello World!")
Run Code Online (Sandbox Code Playgroud)

SRC /包/ util.py

def write(text):
    print(text)
Run Code Online (Sandbox Code Playgroud)

*src/pack/_ init _.py*

EMPTY FILE
Run Code Online (Sandbox Code Playgroud)

当我python pack.pysrc/pack目录运行时,它可以工作(打印"Hello World!").但是,当我python main.pysrc目录运行时,我得到以下异常:

Traceback (most recent call last):
  File ".../src/main.py", line 1, in <module>
    from pack import pack
  File ".../src/pack/pack.py", line 1, in <module>
    import util
ImportError: No module named util
Run Code Online (Sandbox Code Playgroud)

如果我改变了进口线pack.py,以from . import util作为建议,有效相反occours. main.py成功运行,但现在pack.py失败了,提出:

Traceback (most recent call last):
  File ".../src/pack/pack.py", line 1, in <module>
    from . import util
ValueError: Attempted relative import in non-package
Run Code Online (Sandbox Code Playgroud)

我原以为导入是相对于当前位置的,因此你应该能够构建这样的导入链.对我来说,模块应该根据程序的起始位置以不同方式导入兄弟文件,这似乎很奇怪.

有人可以解释为什么这种错误以一种方式而不是另一种方式发生,并且如果有某种方式允许这种文件结构运行我是否想要从main.py或运行pack.py

Len*_*bro 6

在这两种情况下,您都无法进行导入工作.这是因为在一种情况下,您运行pack.py作为主文件,而在另一种情况下,您将其作为包的一部分运行.

当您将其作为独立脚本运行时python pack.py,"pack"目录将添加到PYTHONPATH,这意味着您可以导入其中的任何模块.因此,import util将工作.

运行时python main.py,将src目录添加到PYTHONPATH.这意味着,src例如pack目录中的任何模块或包现在都可以导入.因此from pack import pack.但是,要访问util.py你现在需要做from pack import util.正如你所注意到的,你也可以from . import util在内部做pack.py.

但你不可能同时做到这两点.要么src/是主目录,要么src/pack是.

显而易见但错误的解决方案是让main.py将src/pack目录添加到PYTHONPATH.这将有效,但这不是一个好主意.这样做的正确方法是下定决心.是src/pack一个应该通过导入的模块,import pack还是只是一个包含许多Python脚本的文件夹?决定!:-)

我认为在这种情况下,它显然src/pack应该是一个模块.因此,将其视为一个模块,并确保它像模块一样可用.然后你from pack import util甚至可以pack.py作为主脚本运行.

你是怎样做的?好吧,基本上你要么在你的站点包中安装pack模块,要么你把src目录添加到PYTHONPATH.最后一个是你在开发过程中想要的.您可以手动执行,export PYTHONPATH=<path>也可以让您的测试人员为您执行此操作.你没有testrunner?那么你应该,但这是另一个问题.:)

如果您不再进行开发,请永久安装它,请查看Distribute.它包括一个testrunner.;)