如何使 Python 模块的 __init__.py 将其 help() 委托给同级文件?
Posted
技术标签:
【中文标题】如何使 Python 模块的 __init__.py 将其 help() 委托给同级文件?【英文标题】:How can I make a Python module's __init__.py delegate its help() to a sibling file? 【发布时间】:2019-01-10 19:50:34 【问题描述】:目前我们有一个类似如下的 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)
自动列出所有可用的函数和类。
我想我可以从Ganymede/__init__.py
到execfile("functions.py")
,但我觉得必须有一些更清洁的方法来做到这一点。还是没有?
我需要在 Python 2.7.15 和 3.5.3 中都可以使用的东西。
【问题讨论】:
【参考方案1】:在__init__.py
中创建一个__all__
。
如果您在functions.py
中已经有一个__all__
,您可以直接导入它:
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('_')]
… 或者(相当老套——但如果你有一个 __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
和其他工具报告为您的包的公共成员的内容。
我不确定在没有__all__
的情况下help
的行为是否在任何地方都有记录(交互式help
的工作通常只是很少记录......),它与import
的行为不太一样认为是公开的。
1。好吧,multiprocessing
实际上更聪明/更hacky;它不是从子模块中提取属性,而是从该子模块的动态单例属性中提取属性,该属性在主进程和子进程上设置不同,并相应地更改包的一些***功能......
【讨论】:
有没有办法让我实现这一点,而不必在其__all__
中明确列出functions.py
的每个成员(即,获得help()
的自动查找行为) ?
@Crashworks 是的,如果你不介意有点hacky的话。请稍等,我会修改它。
vars
在这里会不会更好?你什么时候想要set(dir()) - set(vars)
中的一些东西?
@juanpa.arrivillaga 哦,我想我明白了你的要求。如果模块有自定义__dir__
和__getattr__
来导出不在其__dict__
中的动态公共成员,为什么要忽略它们?
哇,感谢您的所有研究!我很感谢你在这方面的时间,但它让我相信我应该把 functions.py
的内容放入 __init__.py
并完成它。以上是关于如何使 Python 模块的 __init__.py 将其 help() 委托给同级文件?的主要内容,如果未能解决你的问题,请参考以下文章
python基础:__init__.py和__init__函数的作用