包__init__.py的相对导入

17

假设我有一个包含两个子模块和大量代码的 __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__方法的绑定方法包装器。我想我可以这样做

from . import __init__ as local_name
local_name = local_name.__self__

为了得到我想要的东西,但(a)让人反感,和(b)这让我担心模块没有完全初始化。

答案需要在Python 2.7和Python 3.4+上都能运行。

是的,清空__init__.py并只从子模块重复导出东西可能更好,但现在还不行。

2个回答

4

对于下划线符号(dunders),没有什么特别的含义(在编写自己的模块/函数名称时,它们只是不被推荐使用); 您应该能够执行以下操作

from .__init__ import my_function as local_name

我不想从__init__.py中导入特定的函数,我想要整个模块。 - zwol
3
明确地导入 __init__ 模块会重新执行该模块,从而产生两个_不同的_模块(pkg is pkg.__init__ 为 False)。每个模块都有自己的命名空间。如果您在 pkg 中更改了某些内容(例如 pkg.config.setSomeValue(...)),它不会影响到 pkg.__init__ 中的对应项。 - mata
2
@mata 这开始感觉像一个错误报告 :-/ - zwol
@zwol 你能做 from .__init__ import * 吗? - maxymoo
@maxymoo 不行,那会在子模块中产生大量的垃圾,并且还需要进行广泛而痛苦的代码更改。 - zwol

1
  • python2 and python3 (uses the discouraged __import__):

    • from 1st level module (pkg.foo, pgk.bar, ...):

      local_name = __import__("", globals(), locals(), [], 1)
      
    • from module in subpackage (pkg.subpkg.foo, ...):

      local_name = __import__("", globals(), locals(), [], 2)
      
  • python3 only*:

    • From pkg.foo or pkg.bar:

      import importlib
      local_name = importlib.import_module("..", __name__)
      
    • From pkg.subpkg.baz:

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

*import_module在Python2中尝试加载pkg.,但在这种情况下不幸地失败了。


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