包 __init__.py 的相对导入

Posted

技术标签:

【中文标题】包 __init__.py 的相对导入【英文标题】:Relative import of package __init__.py 【发布时间】:2017-07-25 16:55:34 【问题描述】:

假设我有一个包含两个子模块的包以及__init__.py 本身中的大量代码:

pkg/__init__.py
pkg/foo.py
pkg/bar.py

并且,为了使计划中的未来重构更容易,我希望包的组件专门使用相对导入来相互引用。特别是,import pkg 永远不应出现。

来自foo.py我可以做

from __future__ import absolute_import
from . import bar

访问bar.py 模块,反之亦然。

问题是,以这种方式导入__init__.py 我要写什么? 我想要与import pkg as local_name 完全相同的效果,只是不必指定绝对名称pkg

#import pkg as local_name
from . import ??? as local_name

更新:受到 maxymoo 回答的启发,我尝试了

from . import __init__ as local_name

这不会将local_name 设置为__init__.py 定义的模块;相反,它获得了似乎是该模块的__init__ method 的绑定方法包装器。我想我能做到

from . import __init__ as local_name
local_name = local_name.__self__

得到我想要的东西,但是 (a) 很糟糕,并且 (b) 这让我担心模块还没有完全初始化。

答案需要在Python 2.7 和 Python 3.4+ 上工作。

是的,最好将__init__.py 挖空并让它从子模块中重新导出内容,但这还不能实现。

【问题讨论】:

【参考方案1】:

dunders 并没有什么特别之处(他们只是在编写您自己的模块/函数名称时感到气馁);你应该能够做到

from .__init__ import my_function as local_name

【讨论】:

我不想从__init__.py 导入特定函数,我想要整个模块 显式导入 __init__ 模块会重新执行该模块,从而产生两个 不同 模块(pkg is pkg.__init__ 为 False)。每个都有自己的命名空间。如果您更改 pkg 中的某些内容(比如 pkg.config.setSomeValue(...) 之类的内容),它不会影响 pkg.__init__ 中的对应项。 @mata 这开始感觉像是一个错误报告:-/ @zwol 你能做from .__init__ import *吗? @maxymoo 不,这会将大量垃圾倾倒到子模块中,并且还需要大量而痛苦的代码更改。【参考方案2】:

python2和python3(使用discouraged__import__):

来自第一级模块(pkg.foopgk.bar,...):

local_name = __import__("", globals(), locals(), [], 1)

来自子包中的模块 (pkg.subpkg.foo, ...):

local_name = __import__("", globals(), locals(), [], 2)

仅限python3*:

来自pkg.foopkg.bar

import importlib
local_name = importlib.import_module("..", __name__)

来自pkg.subpkg.baz

import importlib
local_name = importlib.import_module("...", __name__)

*import_module 在 python2 上尝试加载pkg.,不幸的是。

【讨论】:

以上是关于包 __init__.py 的相对导入的主要内容,如果未能解决你的问题,请参考以下文章

PEP 328“***包之外的相对导入”

ValueError:尝试相对导入超出***包

多级相对导入

PYTHON-DAY18-包 相对 绝对导入

即使使用 __init__.py,如何修复“尝试在非包中进行相对导入”

相对导入兼容性问题 py2 和 py3