如何使Python模块的__init__.py将其help()委托给同级文件?

时间:2018-08-03 00:28:25

标签: python python-import python-module python-packaging

当前,我们有一个类似以下内容的Python库:

Jupiter/
  __init__.py
  Ganymede.py
  Callisto.py

Ganymede.py依次包含函数Foo()Bar()等。我们现有的脚本通过

使用这些功能
from Jupiter import Ganymede
# later in the program...
Ganymede.Foo()

我想重新组织一下,使目录看起来更像

Jupiter/
  __init__.py
  Ganymede/
    __init__.py
    functions.py
  Callisto/
    __init__.py
    functions.py

无需破坏或修改任何使用Jupiter的现有脚本。

如果Ganymede/__init__.py使用"The import system" documentation中所述的导入语法:

from .functions import *

然后,Foo()Bar()最终出现在Ganymede的命名空间中,但是Ganymede的help()没有提及它们。

>>> from Jupiter import Ganymede
>>> dir(Ganymede)
['Bar', 'Foo', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'functions']
>>> help(Ganymede)
Help on package Jupiter.Ganymede in Jupiter:

NAME
    Jupiter.Ganymede

PACKAGE CONTENTS
    functions

FILE
    x:\yadda\yadda\ganymede\__init__.py

我真的很希望help(Ganymede)自动列出所有可用的函数和类。

我想我可以execfile("functions.py")中的Ganymede/__init__.py,但是我觉得必须有一些更清洁的方法来做到这一点。还是没有?

我需要在Python 2.7.15和3.5.3中都可以使用的东西。

1 个答案:

答案 0 :(得分:1)

__all__中创建一个__init__.py


如果__all__中已经有functions.py,则可以将其导入:

from .functions import *
from .functions import __all__

如果要将多个模块合并在一起,则必须更加冗长

from .functions import *
from .classes import *
from . import functions
from . import classes
__all__ = functions.__all__ + classes.__all__

或者,当然,您始终可以保持明确:

from .functions import *
__all__ = ['spam', 'eggs']

或者,如果您想动态构建它:

from .functions import *
from . import functions
__all__ = [name for name in dir(functions) if not name.startswith('_')]

…或(相当hacky,但如果您有一个__init__.py可以从许多子模块中收集名称并且不执行其他操作,则有时会很有用)…

from .functions import *
__all__ = [name for name in globals() if not name.startswith('_')]

…或者您可以变得非常聪明,并以某种方式进行操作,例如multiprocessing可以做到: 1

from . import functions
__all__ = [name for name in functions if not name.startswith('_')]
globals().update({name: getattr(functions, name) for name in __all__})

请记住,__all__也将影响某人执行from Ganymede import *(实际上是that's the main purpose of __all__)时发生的情况,以及inspect和其他工具报告为您包裹的公开成员。

我不确定在没有help的情况下__all__的行为是否在任何地方都有记录(交互式help的作品通常只被轻易记录了……),而且还不是与import认为公开的内容相同。


1。好吧,multiprocessing实际上更聪明/更聪明;它将属性不是从子模块中移出,而是从该子模块的动态单例属性中移出,该属性在主进程和子进程上进行了不同的设置,并相应地更改了程序包的某些顶级功能……