【问题标题】:How to import module inside package如何在包内导入模块
【发布时间】:2020-04-09 03:31:05
【问题描述】:

文件夹结构:

foo/
  bar.py
  __init__.py
test.py

foo/__init__.py 拥有import bar

我正在运行test.py,其中有import foo


如何让__init__.py 导入bar.py

ModuleNotFoundError: No module named 'foo'

为什么 Python 不为我的包创建一个新的作用域并将导入的根设为 foo 目录?

相对路径似乎也不起作用(我收到了SyntaxError),尽管我正在寻找允许绝对路径的解决方案。

import .bar

两个不可接受的答案:

  • 我不能使用import foo.bar。我需要foo 包拥有自己的独立层/范围,这样我就可以在我的计算机中的任何地方移动它并从任何地方导入它。这意味着根目录可能会改变,import foo.bar 并不总是有效。

  • 我无法将 foo 文件夹添加到我的路径中。显然,这会使路径变得混乱,并且很容易发生名称冲突。开始的感觉会说这个包的文件应该与使用它的路径分开。


也许有一种解决方案可以将此包的目录添加到仅适用于该包范围的路径中,在 __init__.py 的某个位置?

【问题讨论】:

  • from . import bar 是正确的语法
  • 哦,谢谢,我现在就用它。我仍然想要一个不需要相对路径的解决方案。
  • @DavidCallanan:你说你不想要相对路径,但你也拒绝import foo.bar,这是进行绝对路径导入的正确方法。 import X总是绝对的;如果你想要相对导入,你必须使用from .Y import X(如果你要导入同级模块/包,Y 可能什么都不是),每个PEP 328
  • @ShadowRanger。打败我
  • @MadPhysicist import foo.bar 是一个绝对路径,但它仍然是相对于项目根目录的。它仍然不是绝对的,我不必输入"C:/Users/Me/Desktop/etc/etc"。同样,我期望import bar 是一个绝对路径,但相对于包根目录而不是项目根目录,对我来说更有意义。

标签: python python-3.x python-import relative-import pep328


【解决方案1】:

根据PEP 328import X 语法纯粹用于绝对导入;因为bar 不是这里的顶级模块,所以唯一有效的import X 语法是import foo.bar

foo__init__.py导入bar的正确方法是:

from . import bar

你关于想要“绝对路径”的观点,但也想要像import .bar 这样的东西是不可能的;即使import .bar 工作,这显然是一个相对路径(因为它仅相对于执行它的模块才有意义;如果在foo 包之外导入.bar 将没有意义)。

至于“为什么 Python 不为我的包创建新的作用域并将导入的根目录设置为 foo 目录?”简单的例子是想象你的子模块被命名为math,而不是bar。做什么:

import math

在这种情况下是什么意思?如果这意味着您的子模块,您如何获得内置的顶级math 模块?这些问题(当我未能包含from __future__ import absolute_import 时,我在 Python 2 代码中遇到过)是为什么 PEP 328 并且存在默认的绝对导入;一种语法始终是绝对的(消除歧义),您可以在需要时使用相对导入语法来执行相对导入(也没有歧义)。

【讨论】:

  • 感谢您的回答。我不想要import .bar,我只是想弄清楚相对路径语法,因为import bar 不起作用,我之前在我的问题中尝试过。我认为 Python 可以很容易地添加另一个字符,例如$ 用于相对于当前包而不是当前目录或项目根目录的路径。
  • @DavidCallanan: . 是相对于当前包的(例如,如果你在foo/bar/baz.pyfrom . import ... 表示“来自foo.bar,包含baz 模块的包”)。 Python 缺少的是相对于项目/包根目录的导入语法(例如,如果您知道 eggs 作为顶级包的直接子级存在,则无法导入 eggs 不知道有多深在包中,您是[为相对导入获取适当数量的点]或顶级包的名称是[用于绝对导入])。他们没有添加它,因为您通常知道其中之一。
  • 是的,如果你不知道绝对路径,你总是知道相对路径,但是相对路径变得乏味。我认为这是一个糟糕的决定,但我可能完全错了。
【解决方案2】:

好的,所以您在import bar 中的__init__.py 文件中有错误,对吗?

好吧,这不应该爆炸,但一个简单的替代方法是 from . import bar

编辑
我理解错误是由于层次结构而发生的,__init__.py 具有顶级层次结构。
我发现以下article 有很大帮助。另请参阅 ShadowRanger's 对此问题的回答。

【讨论】:

  • 谢谢,我现在就用这个​​。我仍在寻找允许绝对路径的解决方案。
  • 我正在尝试对此进行更多分析。你所做的应该有效。
  • 错误与import .bar有关,绝对应该爆炸
  • 你为什么不希望它爆炸呢? foo 的父级在路径中:foo 本身不是...
  • 我不明白这一点。我们显然可以在同一目录中导入其他 python 脚本而无需相对导入。我将 __init__.py 重命名为其他名称,然后它没有爆炸。
猜你喜欢
  • 2013-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-16
相关资源
最近更新 更多