【问题标题】:Unable to import class even though I already have __init__.py files即使我已经有 __init__.py 文件也无法导入类
【发布时间】:2020-06-21 18:10:30
【问题描述】:

我正在尝试将不同目录中的类导入另一个文件,但似乎无法使其正常工作。我知道这个问题被问了很多,我查看了多个 stackoverflow 解决方案和https://docs.python.org/3/tutorial/modules.html#packages

1:Importing files from different folder 2:import python file in another directory failed

我想尝试只使用仅包含 __init__.py 文件的方法,而不是使用 import sys

我的目录结构如下:

django_vue/
  __init__.py
  devices/
        __init__.py
        models.py
  lib/
        __init__.py
        my_file.py

我正在尝试通过以下方式将 Device 类从 /django_vue/devices/models.py 导入到 /django_vue/lib/my_file.py

from devices.models import Device

但是当我这样做时,我仍然收到错误:

from devices.models import Device
ModuleNotFoundError: No module named 'devices'

我不确定我做错了什么,因为我已经在两个目录中都有__init__ 文件。任何帮助表示赞赏。我也在运行 python 3.6。

【问题讨论】:

  • 您是在运行文件、模块还是在运行 django 服务器?你能在这里发布整个错误吗?
  • 另外,作为旁注,__init__.py 文件不再是强制性的,如果我没记错的话,来自 python3.6
  • 我只是在运行一个文件。所以从终端我只是在导航到django_vue/lib/后做python my_file.py
  • 好的。这就是问题所在。如果可以的话,让我尝试解决问题。

标签: python python-import


【解决方案1】:

这是我正在使用的文件夹结构。

.
└── django_vue
    ├── devices
    │   └── models.py
    └── lib
        └── file.py

当你跑步时

$ python file.py

python 无法知道目录之外的内容。

python 不能像那样返回然后进入devices/

解决此问题的最简单方法是将文件夹 devices/ 添加到 sys.path。当 python 导入一个模块时,它会从sys.path 中搜索该模块。添加devices/ 的路径将使其可用于导入。

这是我的文件。

# models.py
Device = 'device'
# file.py
import sys
sys.path.append('..')  # adds the parent dir (which is django-vue/) to path
# django-vue dir has devices/ so now this is available for imports

# importing this works now
from devices.models import Device

print(Device)

输出

django_vue/lib$ python3 file.py 

device

【讨论】:

  • 在那之后我得到了一个 Django 错误,但我想我一定是错误配置了一些东西。它不再给我同样的错误,所以我认为它有效。谢谢。
【解决方案2】:

想想你在my_file.py 里面,然后导入一个叫做devices 的东西。 python 怎么会知道 devices 这个名字是从哪里来的。 它不会在您的整个云端硬盘中搜索该模块/包

相对导入

改为使用相对导入。写from ..devices.models import Device。这是告诉 python 上一个目录到父目录,在那里它会找到devices 包。您的 lib 模块现在应该作为 模块

工作

如果你直接运行 my_file.py 包(如python C:/django_vue/lib/my_file.py您仍然会收到错误消息。不一样的错误;新错误将类似于

ImportError: attempted relative import with no known parent package

这是因为您实际上正在运行my_file.py

如果您考虑一下,当 my_file.py 显然是包的一部分时,为什么要单独运行它。也许您只是在测试使用包时导入是否有效。这样做的问题在于,它使您的包相对导入看起来不起作用即使这确实有效

在 django_vue 中创建一个main.py 并写入from lib import my_file。这将运行您的my_file.py,您会发现没有错误。

这里发生了什么

你听说过__package__吗?

如果您将print(str(__package__)) 放入您的my_file.py 并直接运行my_file.py,您将看到它打印出None

但是,如果您运行main.py(您刚刚创建的),您会看到当它到达my_file.py 时,__package__ 实际上会被定义为某个东西。

啊…… 你现在明白了,这一切都说得通了;你最初得到的错误是关于no known parent package。如果__package__ 未定义,则意味着没有相对父包,因为该文件显然是直接运行的,而不是作为包的一部分。

考虑绝对导入

您可能还想考虑使用绝对导入,因为如果您正在处理包,您可能会在开发时更改它的目录结构。因此您需要不断更改受影响文件的导入引用。

虽然你可以找到带有 python 扩展的 IDE,当你改变你的目录时,它会自动出现。我相信VS Code 会自动执行此操作。

【讨论】:

    【解决方案3】:

    __init__ 文件替换为__main__

    【讨论】:

    • 您的建议不符合相同的目标,init 文件用于集成其他 .py 文件。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-29
    • 2021-07-28
    • 2016-11-26
    相关资源
    最近更新 更多