如何使 Python 模块的 __init__.py 将其 help() 委托给同级文件?
How can I make a Python module's __init__.py delegate its help() to a sibling file?
目前我们有一个 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 中都可用的东西。
在 __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('_')]
… 或(相当 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
和其他工具报告的内容作为您的包的 public 成员。
我不确定在没有 __all__
的情况下 help
的行为在任何地方都有记录(交互式 help
作品一般只被少量记录......),而且它没有与 import
认为的 public.
完全相同
1.好吧,multiprocessing
实际上比 clever/hacky 多很多;它不是从子模块中提取属性,而是从该子模块的动态单例属性中提取属性,该子模块在主进程和子进程上设置不同,并相应地更改包的一些顶级函数…
目前我们有一个 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 中都可用的东西。
在 __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('_')]
… 或(相当 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
和其他工具报告的内容作为您的包的 public 成员。
我不确定在没有 __all__
的情况下 help
的行为在任何地方都有记录(交互式 help
作品一般只被少量记录......),而且它没有与 import
认为的 public.
1.好吧,multiprocessing
实际上比 clever/hacky 多很多;它不是从子模块中提取属性,而是从该子模块的动态单例属性中提取属性,该子模块在主进程和子进程上设置不同,并相应地更改包的一些顶级函数…