【问题标题】:How to make `from . import utils` work如何从 .导入 utils 工作
【发布时间】:2014-07-18 13:18:54
【问题描述】:

我的目录结构如下:

some-tools-dir/
    base_utils.py
    other_utils.py
    some-tool.py
    some-other-tool.py

some-other-tools-dir/
    basetools -> symlink to ../some-tools-dir
    yet-another-tool.py

other_utils.py,我有:

import base_utils

现在,在yet-another-tool.py,我想做:

import basetools.other_utils

这不起作用,因为 Python 无法将 basetools 识别为 Python 包。 所以我添加了一个空的basetools/__init__.py。 现在,在other_utils 中,我得到了异常:

    import base_utils
ImportError: No module named base_utils

所以我把那行改成:

from . import base_utils

yet-another-tool.py 现在可以使用了。

但是,some-tool.py 不再起作用。它导入other_utils,我得到了异常:

    from . import base_utils
ValueError: Attempted relative import in non-package

现在,我可以将这个 hack/workaround 添​​加到 some-tools-dir/*-tool.py

import os, sys
__package__ = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
sys.path += [os.path.dirname(os.path.dirname(os.path.abspath(__file__)))]
__import__(__package__)

此外,使所有本地导入在这些文件中相对。

我想这解决了问题。但是,它看起来有些难看,我必须修改sys.path。我尝试了这个 hack 的几种变体,但是,如果可能的话,我想支持多个 Python 版本,所以使用模块 importlib 变得很复杂,尤其是。因为我有 Python 3.2,我不喜欢使用模块 imp,因为它已被弃用。而且,它似乎只会变得更加复杂。

我有什么遗漏吗?对于一个似乎并不罕见(对我来说)的用例来说,这一切看起来都很难看而且太复杂了。我的 hack 有更简洁/更简单的版本吗?

我愿意做的一个限制是只支持 Python >=3.2,如果这样可以简化任何事情的话。

【问题讨论】:

    标签: python python-3.x python-import


    【解决方案1】:

    (请注意,此答案是通过将来自 this answerthis question 的信息拼凑而成的,所以如果你喜欢,请给他们投票)

    这看起来不那么老套,至少适用于 Python 2.7+:

    if __name__ == "__main__" and __package__ is None:
        import sys, os.path as path
        sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
    
    from some_tools_dir import other_utils
    

    我认为你觉得这很困难的主要原因是因为在 python 包中包含可执行脚本实际上是不寻常的。 Guido van Rossum 实际上将其称为"antipattern"。通常你的可执行文件位于包的根目录之上,然后可以简单地使用:

    from some_tools_dir import other_utils
    

    没有任何大惊小怪。

    或者,如果你想执行一个存在于包中的脚本,你实际上将它作为包的一部分调用(同样,从包的父目录):

    python -m some_tools_dir.other_utils
    

    【讨论】:

    • 请注意,我在问题中有意使用带有“-”的目录名称,因为我想要一个通用的解决方案。您的解决方案假定它是一个有效的包名称 (some_tools_dir)。 --- 但是,我决定重组我的文件并遵循 Guidos 的建议。此外,python -m 不是真正的解决方案,因为我希望能够让脚本可执行,但我不知道如何通过 hashbang 来实现。
    【解决方案2】:

    您能否将顶级根路径添加到 PYTHONPATH 中?

    如果是这样,您可以添加

    __init__.py
    

    文件到 some-tools-dir(和/或 some-other-tools-dir)

    然后从 other_utils.py 你做

    from some-tools-dir import base_utils
    

    而在又一个工具.py 中你可以这样做

    from some-tools-dir import other_utils
    

    然后您可以删除符号链接,并具有适当的命名空间。

    【讨论】:

    • 我已经这样做了。这就是我在我的问题中写的。此外,您的代码不起作用,因为模块名称不能包含"-"
    猜你喜欢
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    • 2020-11-08
    • 2021-07-05
    • 2012-08-20
    • 1970-01-01
    • 2022-12-21
    • 2021-07-12
    相关资源
    最近更新 更多