【问题标题】:How to do a relative import from the parent directory?如何从父目录进行相对导入?
【发布时间】:2017-11-17 01:35:07
【问题描述】:

我已经搜索过这个并找到了很多答案,所有这些都告诉我要做我正在做的事情,这是我的目录结构:

app/
+-- __init__.py
+-- app_manager.py
+-- app_gui/
|   +-- __init__.py
|   +-- app_gui.py

在 app_gui.py 我有:

import tkinter as tk
from tkinter import ttk
from app_manager import AppManager

在应用管理器中:

class AppManager():
    def __init__(self):
    """ default constructor for app manager """

在 Visual Code 中,它实际上将其解析为自动完成,这告诉我至少 Visual Code 认为它已正确完成。但是,如果我运行它,我会收到以下错误:

ModuleNotFoundError: No Module named "app_manager"

编辑

更改为from app.app_manager import AppManager 时的完整堆栈跟踪:

Traceback (most recent call last):
   File ".\app_gui\app_gui.py", line 4, in <module>
     from app_manager import AppManager
ModuleNotFoundError: No module named 'app_manager' 

【问题讨论】:

  • 你的__main__在哪里?
  • @Mark 我试过把它放在 app_gui 和 app_manager 中,都给我同样的错误,子包不能导入任何东西(即使它们在同一个目录中)
  • 在你的搜索中你读过Relative imports for the billionth time吗?

标签: python relative-import


【解决方案1】:

由于app_manager.pyapp_gui.py 上方的目录,我相信您的导入(如果您希望使用相对导入)应该是

from ..app_manager import AppManager

编辑以解决 cmets 中的错误:如果您尝试直接运行此文件,您将在 cmets 中获得 ValueError。相对导入在包内的模块之间起作用。假设你使用了我上面写的导入,然后你有一个比你的app 目录更上一层的文件,名为stuff.py,内容如下:

import app.app_gui.app_gui
print('hello')

运行stuff.py 看起来像:

$ python stuff.py 
hello

换句话说,直接使用 python 解释器执行具有相对导入的文件将导致错误,因为它不打算以这种方式使用。相反,您的模型应该由模块本身之外的东西导入和执行。

如果您的app 目录中有一个__main__ 文件,其中包含完全相同的代码,您也可以直接执行该模块。

$ cat app/__main__.py 
import app.app_gui.app_gui
print('hello')

$ python -m app
hello

【讨论】:

  • "ValueError: 尝试相对导入超出顶级包"
  • python app_gui.py 当主要在 app_gui.py 中时,python app_manager.py 当我尝试将它切换到 app_manager.py 时
  • 已编辑答案以解决此问题。如果您仍有疑问,请告诉我。
  • 是的,很抱歉,进行了很多修改,但现在这应该对你有好处,而且可能是 TMI 哈哈。
【解决方案2】:

像这样运行 python 代码充其量只是 hacky。

使用setup.py
这将需要一些小的改动,但会立即带来好处。
然后,您将能够像使用任何其他已安装的软件包一样使用您的 app 软件包。

新目录结构

.
├── app
│   ├── app_gui
│   │   ├── app_gui.py
│   │   └── __init__.py
│   ├── app_manager.py
│   └── __init__.py
└── setup.py

setup.py

​​>
from setuptools import find_packages, setup

setup(name='app',
      version='0.0.1-dev',
      description='My app package',
      install_requires=['tkinter'],
      packages=find_packages(),
      zip_safe=False)

app_gui.py

​​>
from app.app_manager import AppManager

manager = AppManager()

把它们放在一起

从与setup.py 相同的目录运行:
$&gt; python setup.py develop

这会将包符号链接到您的 site-pacakges 文件夹中,您可以像对待任何其他包一样对待它。即使用import app 从系统上任何位置的脚本导入它。

【讨论】:

  • 好的,谢谢,那么在这种情况下 main 应该放在哪里?
  • @Aserian 这取决于您打算如何使用该软件包。通常我会有一个单独的main.py 导入包并在__main__ 中使用它。这个函数可能会做类似import app app.run()
猜你喜欢
  • 2012-05-28
  • 2021-08-15
  • 1970-01-01
  • 2021-12-04
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 2012-07-12
  • 2013-11-09
相关资源
最近更新 更多