Python中的相对导入

30

大家好——我在使用Python的相对导入时非常苦恼。我已经阅读了文档30次以及其他论坛上的帖子,但似乎仍然无法正常工作。

我的目录结构目前是这样的:

src/
    __init__.py
    main.py
    components/
        __init__.py
        expander.py
        language_id.py
    utilities/
        __init__.py
        functions.py

我想让expander.py和language_id.py可以访问functions模块。 我运行python main.py,使用“from components.expander import *”和“from components.language_id import *”可以很好地访问这些模块。

但是,在expander和language_id内部访问functions模块的代码:

from ..utilities.functions import *

我收到了这个错误:

ValueError: Attempted relative import beyond toplevel package

我已经反复检查了很多次,似乎遵循了文档。 有没有人知道这里出了什么问题?


9
你已经找到了解决方案,但为了解释为什么需要这样做:这个包应该是完全自包含的。当你在其中运行 main.py 时,它不会将 src/ 视为一个包。 - Thomas K
1个回答

22

算了,我解决了:

src/
    main.py
    mod/
        __init__.py
        components/
            __init__.py
            expander.py
            language_id.py
        utilities/
            __init__.py
            functions.py

main.py 然后将子包称为:

from mod.components.expander import *
from mod.utilities.functions import *

expander.py和language_id.py可以通过functions.py进行访问:

from ..utilities.functions import *

但有趣的是,我在components目录中有一个文本文件,expander.py使用该文件。然而,在运行时,即使文件在相同的目录下,它也无法定位到该文件。我将文本文件移动到main.py所在的相同目录中,它就工作了。看起来有些违反直觉。


18
所有新的模块导入功能都存在问题,不够直观易懂。 - Matt Joiner
3
打开文本文件是从程序启动的工作目录开始的,而导入则相对于脚本的位置。您可以在模块中使用__file__来查找其路径,因此可以引用同一目录中的内容,但这并不是非常优雅的做法。如果文本文件是程序的静态数据,则将其制成Python模块并进行导入可能会更容易。 - Thomas K
1
您可以使用 pkgutil.get_data() (http://docs.python.org/library/pkgutil#pkgutil.get_data) 函数,通过模块命名空间来定位文件并检索它们。例如,raw_data = pkgutil.get_data('mod.components', 'data.txt') 将会从文件中检索原始二进制数据。 - ncoghlan
对于那些仍然发现这个答案有效的人,这对我有用:sys.path.append(path) - Forethinker
解决方案是删除项目根目录中的__init__文件。创建一个名为“mod”的新文件夹是不必要的。 - Giulio De Marco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接