python中模块的相对路径

Posted

技术标签:

【中文标题】python中模块的相对路径【英文标题】:relative paths for modules in python 【发布时间】:2017-08-10 22:42:28 【问题描述】:

我尝试了一些不同的技术来尝试做一些对我来说似乎可行的事情,但我想我错过了一些关于 python 的陷阱(使用 2.7,但如果可能的话,我希望这也适用于 3.*)。

我不确定包或模块之类的术语,但对我来说,以下似乎是一个非常“简单”的可行方案。

这是目录结构:

.
├── job
│   └── the_script.py
└── modules
    ├── __init__.py
    └── print_module.py

the_script.py的内容:

# this does not work
import importlib
print_module = importlib.import_module('.print_module', '..modules')

# this also does not work
from ..modules import print_module

print_module.do_stuff()

print_module的内容:

def do_stuff():
    print("This should be in stdout")

我想将所有这些“相对路径”的东西运行为:

/job$ python2 the_script.py

但是importlib.import_module 给出了各种错误:

如果我只使用 1 个输入参数..modules.print_module,那么我得到:TypeError("relative imports require the 'package' argument") 如果我使用 2 个输入参数(如上例所示),那么我得到:ValueError: Empty module name

另一方面,使用from ..modules 语法我得到:ValueError: Attempted relative import in non-package

我认为 __init__.py 空文件应该足以将该代码限定为“包”(或模块?不确定术语),但我似乎缺少关于如何管理相对路径的一些东西。

我读到过去人们使用pathimport osimport sys 中的其他函数来破解它,但根据官方文档(python 2.7 和 3.*),这应该不再需要了.

我做错了什么,如何实现打印内容modules/print_module.do_stuff 从“相对目录”job/ 中的脚本调用它的结果?

【问题讨论】:

为什么要在这里使用 importlib?为什么不直接导入呢? __init__.py 只为其所在的目录创建一个包。您需要将__init__.py 添加到您显示的树中的所有 目录中。您还需要确保包含***包目录的目录位于sys.path 上,并且如果您希望能够将其中一个文件作为脚本执行,则需要考虑所描述的问题@ 987654321@ 和 here. 【参考方案1】:

我找到了使用sysos 的解决方案。

脚本the_script.py应该是:

import sys
import os
lib_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '../modules'))
sys.path.append(lib_path)

# commenting out the following shows the `modules` directory in the path
# print(sys.path)

import print_module

print_module.do_stuff()

然后无论我在路径中的哪个位置,我都可以通过命令行运行它,例如:

/job$ python2 the_script.py <...>/job$ python2 <...>/job/the_script.py

【讨论】:

谢谢。说得通。也令人费解:几乎就像他们故意制造的东西,所以你不能使用相对路径进行导入(或者必须跳过箍才能这样做)。【参考方案2】:

如果您在此处遵循本指南的结构:http://docs.python-guide.org/en/latest/writing/structure/#test-suite(强烈建议全部阅读,这很有帮助)您会看到:

要为各个测试提供导入上下文,请创建一个 tests/context.py 文件:

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

import sample

然后,在各个测试模块中,像这样导入模块:

from .context import sample

无论安装方法如何,这将始终按预期工作。

在你的情况下翻译这意味着:

root_folder
├── job
│   ├── context.py <- create this file
│   └── the_script.py
└── modules
    ├── __init__.py
    └── print_module.py

context.py 文件中写入上面显示的行,但是import modules 而不是import samples

终于在您的the_script.py:from .context import module 中,您将准备出发!

祝你好运:)

【讨论】:

谢谢 :) 但这给出了:ImportError: No module named modules.print_module 在 python 2 中,这给出了ImportError: No module named airflow_stuff.modules.print_module,在 python 3 中,它给出了类似的错误消息 通过sys.path 使用上下文的这种方式给出了ValueError: Attempted relative import in non-package,很抱歉一直指出这些细节,但它似乎不起作用,但是我找到了一个类似的解决方案,我在此处的答案中发布虽然它看起来很接近你的所以不知道为什么在你的情况下它会引发错误。【参考方案3】:

如果您不确定术语,请参阅非常好的教程:

http://docs.python-guide.org/en/latest/writing/structure/#modules

http://docs.python-guide.org/en/latest/writing/structure/#packages

但是对于你的结构:

.
├── job
│   └── the_script.py
└── modules
    ├── __init__.py
    └── print_module.py

只要在the_script.py说:

import sys
sys.append('..')
import modules.print_module

这会将父目录添加到 PYTHONPATH,python 将看到目录“平行”到作业目录,它会工作。

我认为在最基本的层面上知道以下内容就足够了:

    package 是任何带有__init__.py 文件的目录 module 是带有.py 的文件,但是当您导入模块时,您会省略扩展名。

【讨论】:

感谢您指出文档 :) 但这给出了:ImportError: No module named modules.print_module 在 python 2 中,这给出了AttributeError: 'module' object has no attribute 'append',但是如果我改为使用sys.path.append('..'),那么这给出了ImportError: No module named modules.print_module。在 python 3 中,它给出了类似的错误消息。

以上是关于python中模块的相对路径的主要内容,如果未能解决你的问题,请参考以下文章

在Python中以绝对路径或者相对路径导入文件(或模块)的方法

当 CWD 发生变化时,如何在 Python 模块中使用相对路径?

python学习的第十八天模块之包相对搜索路径和绝对搜索路径

模块之相对路径导入

Python 包内的导入问题(绝对导入和相对导入)

详解Python中的相对导入和绝对导入