从不同子文件夹的子文件夹中相对导入Python模块

8 投票
2 回答
6393 浏览
提问于 2025-04-17 14:40

我正在尝试使用 alembic,这是一个在 Python 中与 sqlalchemy 一起使用的工具。你输入一个命令,它会生成一个名为 "alembic" 的文件夹,里面有一些 py 文件。里面的 py 文件需要链接到我在一个叫 "myapp" 的单独文件夹中的应用程序。但是我无法链接,系统提示说它不存在,而且相对导入也不管用。

所以我需要从 myapp/configs/config.py 文件中导入我的配置类。

/apps
+--/alembic
|----env.py <--- the calling file
+--/myapp
|----configs/__init__.py <--- has "DefaultConfig" class imported
|----configs/config.py <--- I want to import the class inside here.

在 env.py 文件里面:

from myapp.configs import DefaultConfig

这样做不行。

我尝试过:

from ..myapp.configs import DefaultConfig

还是没有成功。

在 alembic 文档中的示例代码说只需要使用 "myapp.whatever"。

我甚至把我的 "/apps" 和 "/myapp" 添加到了环境变量中的 PYTHON_PATH。

示例错误:

File "D:\apps\myapp\lib\site-packages\alembic\command.p
y", line 97, in revision
    script.run_env()
  File "D:\apps\myapp\lib\site-packages\alembic\script.py
", line 191, in run_env
    util.load_python_file(self.dir, 'env.py')
  File "D:\apps\myapp\lib\site-packages\alembic\util.py",
 line 186, in load_python_file
    module = imp.load_source(module_id, path, open(path, 'rb'))
  File "alembic\env.py", line 5, in <module>
    from ..myapp.configs import DefaultConfig as conf
ValueError: Attempted relative import in non-package

2 个回答

0

你的 myapp 是一个独立的应用程序,还是像 Django 里那种子应用呢?如果它是一个独立的应用,那你现在的做法可能有点问题。你真正需要做的是安装你的应用所依赖的库,这样你就可以直接使用它们,而不必用相对导入这种方式(这种做法不好,尤其是当别人也在使用你的应用时)。

如果它是独立的应用,你可能想要做的事情有:

  • 为你的应用设置一个虚拟环境(我强烈推荐使用 virtualenvwrapper,我刚在我的新博客里写过这个,虽然还没写完):http://demianbrecht.github.com/posts/2013/01/02/virtualenvwrapper/
  • 安装 alembic 作为依赖:pip install alembic
  • 创建一个 requirements.txt 文件:pip freeze > requirements.txt

现在,你应该可以在项目的任何地方通过 import alembic 来使用 alembic 了。

补充说明

你的目录结构也有点问题。你需要把所有与应用相关的模块放到另一个 myapp 子目录里:

myapp
    myapp
        __init__.py
        configs/__init__.py

这样做的原因是,你可以把 myapp 加入到你的 PYTHONPATH 中,这样就可以通过 from myapp import foo 来导入你应用里的任何模块。现在的情况是,如果 myapp 在你的 PYTHONPATH 中,你只能从第二个命名空间层级访问子模块(也就是说只能用 import configs),这显然是不好的。

9

你有两种解决问题的方法:

修改你的 PYTHONPATH 环境变量

你可以通过在终端运行以下 BASH / SH 命令来添加应用程序目录的路径:

$ export PYTHONPATH=$PYTHONPATH:'/path/to/apps'

请注意,直接将路径添加到 PATH 环境变量是无效的。如果你想了解更多关于 PYTHONPATH 的信息,如何管理它,以及关于模块的一些友好的介绍,可以查看:

http://www.stereoplex.com/blog/understanding-imports-and-pythonpath

不过请注意,这种方法会影响你系统的 PYTHONPATH。强烈建议使用虚拟环境(virtualenv),这样如果出现问题,就不会影响到整个系统和其他应用程序。当使用 virtualenvwrapper 时:

$ add2virtualenv '/path/to/apps'

更多信息请查看 这里

在 Python 脚本内部添加路径

另外,你也可以在脚本运行时添加路径,方法是:

import sys
sys.path.append('/path/to/apps')

将其添加到你的 apps/alembic/env.py 文件中。

最后,在同一个文件中,做以下更改:

from myapp.configs.config import DefaultConfig

请注意,你的 apps/myapp 文件夹中也应该包含一个 __init__.py 文件(可以是空的),这样 Python 才会把它当作一个模块,正如 Demian Brecht 所指出的。

撰写回答