Python 函数导入在使用 Spyder 的 Django 中不起作用



我的 Django 项目有以下文件夹结构,其中controllers是我保存所有自定义.py文件的地方:

C:.
│   db.sqlite3
│   manage.py
│
├───myApp
│   │   admin.py
│   │   apps.py
│   │   forms.py
│   │   models.py
│   │   tests.py
│   │   urls.py
│   │   views.py
│   │   widgets.py
│   │   __init__.py
│   │
│   ├───controllers
│   │   │   helpers.py
│   │   │   function.py
│   │   │   __init__.py
│   │   │

controllers/function.py里面我想导入文件helpers.py.

场景 1:如果我键入from .helpers import foo并在 Django 中运行它,那么我可以导入 helpers.py,但是如果我在 Spyder 中运行相同的导入,那么我会得到:ImportError: attempted relative import with no known parent package

场景 2:如果我键入from helpers import foo(没有"点")并在 Django 中运行它,那么我会得到:ModuleNotFoundError: No module named 'helpers'但它在 Spyder 中有效!

我在这里缺少路径(或相对路径)的内容。我需要能够有一个在Django和Spyder中工作的python脚本,而不必在任何地方删除.

问:"如果我在Spyder中运行相同的导入" => 你的意思是在Spyder的集成Python shell中吗? 答:"正确">

那么这是意料之中的。

在 functions.py 模块中,您可以使用相对导入(这实际上是您想要的),因为它将相对于当前模块("functions.py")进行解析。

当你在交互式 shell 中时,你不在作为包一部分的模块中,所以相对导入在这里不起作用,你必须使用绝对导入(或相对于当前工作目录的导入,这应该是你sys.path中的第一个 - 当然,除非有什么东西(IDE 或其他)弄乱了它。

低:

  • 在您的模块中,保留显式相对导入(它应该始终有效并解析为正确的"帮助程序"模块或子包)
  • 在 shell 中,使用与当前sys.path匹配的限定路径

编辑

我不完全理解你所说的"明确的相对导入"和"合格路径"是什么意思

"显式相对导入":from .helpers import foo- 这是一个相对导入(相对于functions模块),并且是显式的(使用的语法明确表示"在与我相同的包中查找'帮助程序'模块或子包,并且处于同一级别")

"合格的路径":嗯,是的,我想这不是最好的公式。我的意思是使用从包顶部到模块的完整 python 限定路径进行"或多或少绝对"导入。关键是,构成"您的软件包顶部"的内容取决于您sys.path中的内容,而这反过来可能(或不取决于几个因素)取决于您当前的工作目录。

默认情况下,python 将当前目录插入sys.path的第一个位置。然后,它使用sys.path查找模块或包(警告:sys.path中列出的路径不应是包的完整路径,而应是包含包的目录的路径)。

IOW,如果你打开一个终端,cd到你的django的项目根目录并启动一个(标准的)python shell,你的项目的根将在sys.path中排在第一位,你的helpers模块的限定名称将是myapps.controllers.helpers。但是,如果您在myapps而不是,那么完整的路径将是controllers.helpers...

唯一理智的方法实际上是确保你永远不会在你的sys.path中直接拥有任何项目的包路径(IOW 始终从项目的根目录运行你的代码)。这不仅解决了那些讨厌的进口问题,还避免了臭名昭著的"双重进口陷阱">

"在 functions.py 模块中,您可以使用相对导入"。你的意思是我可以使用.?

是的。实际上,除非您有令人信服的理由不使用它,否则您甚至应该使用它,因为它将防止sys.path中之前的另一个同名模块对helpers模块的潜在阴影 - 并且它非常明确地表明您要从哪个helpers模块或包导入。

这是我在场景 1 中所做的,它在 Spyder 中不起作用。

正如我在评论中已经提到的,"在Spyder中不起作用"不足以确切地说出问题所在,因为我们不知道您正在做什么"在Spyder中不起作用"- 也没有确切的错误消息和完整的回溯FWIW,这两者都通常是"不起作用"问题所必需的(当然,除非问题很明显)。

但是,如果它是(据我所知)"在 Spyder 中启动 python shell 并键入from . helpers import xxx",那么它确实不会"工作" - 您只能在模块代码中使用此语法,并且模块必须是包的一部分,并且包含此包的目录必须在您的sys.path中。

这就是为什么在python shell中,你必须使用绝对导入("from xxx import yyy")。但是,确切的路径取决于您sys.path中的内容 - 这部分取决于您当前的工作目录(至少对于普通的Python shell - 我不使用 Spyder,所以我无法判断它在背后做什么)。

现在,如果 Spyder 不是完全脑死亡的,它应该使用 django 项目的根作为sys.path的第一个元素(或者至少在sys.path中拥有这个目录),所以完整的限定路径 (from myapp.controllers.helpers import foo)应该可以工作。如果没有,请检查您的 cwd (os.getcwd()) 和您的sys.path,然后使用以下方法编辑您的问题:

  • 完整描述您正在做什么
  • 确切的错误消息和完整的回溯
  • 您的 CWD 和系统路径

另外,你可能想阅读一些关于Python导入系统的文档 - 公平地说,它有时可以是一个特大号的PITA。

一个 Try Except 子句应该这样做:

try:
from .helpers import foo
except ImportError:
from helpers import foo

最新更新