【问题标题】:Python function import not working in Django using SpyderPython函数导入在使用Spyder的Django中不起作用
【发布时间】:2020-02-19 23:53:12
【问题描述】:

我的 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 中运行同样的导入,我会得到:@987654327 @

场景 2: 如果我输入 from helpers import foo(不带“点”)并在 Django 中运行它,我会得到:ModuleNotFoundError: No module named 'helpers' 但它在 Spyder 中有效!

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

【问题讨论】:

  • 我在两个应用程序中都运行 python3 print(sys.version) 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
  • "如果我在 Spyder 中运行同样的导入" => 你的意思是在 spyder 的集成 python shell 中吗?
  • @brunodesthuilliers 正确

标签: python django spyder


【解决方案1】:

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

那么这是意料之中的事。

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

当您在交互式 shell 中时,您不在作为包一部分的模块中,因此相对导入在此处无法工作,您必须使用绝对导入(或相对于当前工作目录的导入,这应该在你的sys.path 中排在第一位——当然,除非有什么东西(IDE 或其他)弄乱了它。

IOW:

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

编辑

我不完全理解“显式相对导入”和“合格路径”的意思

"explicit relative import" : from .helpers import foo - 它是一个相对导入(相对于 functions 模块),而且它是显式的(使用的语法明确表示“在同一个包中寻找一个‘帮助者’模块或子包和我一样,处于同一水平”)

“合格路径”:是的,我猜这不是最好的表述。我的意思是使用从包顶部到模块的完整 python 限定路径进行“或多或少绝对”导入。关键是什么构成“你的包的顶部”取决于你的 sys.path 中的内容,而这又可能(或不,取决于几个因素)取决于你当前的工作目录。

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

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

实际上,唯一明智的方法是确保您的任何项目包路径都不会直接位于您的sys.path 中(IOW 始终从项目的根目录运行您的代码)。这不仅解决了那些讨厌的导入问题,还避免了臭名昭著的"double import trap"

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

是的。实际上,您甚至应该使用它,除非您有令人信服的理由不这样做,因为它可以防止 helpers 模块被您的 sys.path 之前出现的另一个同名模块隐藏- 它非常明确地表明您从哪个helpers 模块或包导入。

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

正如我在评论中已经提到的那样,“在 Spyder 中不起作用”不足以告诉确切出了什么问题,因为我们不知道确切你是什么'正在这样做“在 Spyder 中不起作用” - 也不是 exact 错误消息和完整的回溯 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 和 sys.path

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

【讨论】:

  • 我不完全理解“显式相对导入”和“合格路径”的含义。冒着误解的风险,您能否通过输入我应该作为导入语法的内容来澄清一下,即from ?helpers import foo
  • "在 functions.py 模块中,您可以使用相对导入"。你的意思是我可以使用.?这就是我在场景 1 中所做的,它在 Spyder 中不起作用。
【解决方案2】:

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

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

【讨论】:

  • 这在 Spyder 中不起作用,我得到:ModuleNotFoundError: No module named 'myApp'。它可以在 Django 中工作,但不能在 Spyder 中工作。如果您仔细阅读,我的问题是一个明显的不一致之处,即我能够隔离一个适用于 Django 但不适用于 Spyder 的场景和另一个适用于 Spyder 但不适用于 Django 的场景。
  • 那么在这种情况下,你有没有尝试过,除了子句?我会更新答案
  • 似乎经过数小时的研究,我可能需要执行此 hack... 仍然无法解释为什么 Django 坚持使用 .
  • @gmarais Django 和 Spyder 处理导入的方式肯定存在根本差异。如果您认为此解决方案可能对其他人有所帮助,我可以建议您从该答案中删除反对票吗?
  • 我没有投反对票。也就是说,尊重,我不是要求解决方法。我需要了解这个问题,因为这将部署在生产环境中,简单的“解决方法”是不可接受的。
猜你喜欢
  • 2018-06-10
  • 1970-01-01
  • 2019-07-02
  • 1970-01-01
  • 1970-01-01
  • 2019-06-13
  • 2019-04-27
  • 2020-09-13
  • 1970-01-01
相关资源
最近更新 更多