如何在Python中打印“__main__”的帮助说明?

How Can I Print The Help Description Of "__main__" In Python?

对于引入的模块,在解释器中调用help(<module_name>)会打印模块的描述;通常,这是一个文档字符串,但如果模块以注释开头,它会将这些作为描述传递。在未导入的脚本中(即任何带有 __main____name__ 的脚本),调用 print(__doc__) 将给出类似的结果——但前提是存在文档字符串;它不会像 help() 那样提取任何评论。

那么如何在脚本本身上调用 help() 并获取描述,尤其是在没有适当的文档字符串而只有注释的情况下?

您可以使用模块可用的事实 sys.modules['__main__']:

"""
Is this what you want?
"""
import sys

if __name__ == '__main__':
    help(sys.modules['__main__'])

产出

Help on module __main__:

NAME
    __main__ - Is this what you want?

DATA
    __annotations__ = {}

FILE
    /Users/akx/Desktop/so61453557.py

(END)

或者,对于没有文档字符串但有注释的文件:

# This is
# the description
# and not even a haiku

import sys

if __name__ == '__main__':
    help(sys.modules['__main__'])
Help on module __main__:

NAME
    __main__

DESCRIPTION
    # This is
    # the description
    # and not even a haiku

DATA
    __annotations__ = {}

FILE
    /Users/akx/Desktop/so61453557.py

(END)

编辑

好的,结果比我想象的更有趣,并且深入研究了 CPython 的内部结构!

python -i so61453557.pypython -m so61453557 在这里的行为不同。

前者调用pymain_run_file(),后者调用PyRun_AnyFileExFlags(),后者调用PyRun_SimpleFileExFlags()。据我所知,它基本上合成了一个 __main__ 模块并使用 PyRun_FileExFlags 在该上下文中评估文件。

后者调用pymain_run_module(),其真正的逻辑包含在stdlib runpy.py模块中(_run_module_as_main)。

之后,

-i 被设置时(interactiveinspect),pymain_repl() 被调用,如果设置它可能会调用一个交互式挂钩(例如 readline 完成和东西) , 然后调用 PyRun_AnyFileFlags(stdin, "<stdin>", cf).

我不知道在文件运行之后清除了__main__(可能是PyRun_SimpleFileExFlags末尾的XDECREF()),但是这里有一些结论。

  • python -i -m so61453557 似乎保留了 __main__ (<module '__main__' from 'so61453557.py'>),所以你可以 运行 help(sys.modules['__main__']) 正如你在 REPL 中所期望的那样。
  • python -i so61453557.py:进入 REPL 时,__main__ 模块恢复为 <module '__main__' (<_frozen_importlib_external.SourceFileLoader object at 0x10fb2e990>)>
  • python 有第三个版本的 __main__<module '__main__' (built-in)>.

作为黑客,我认为可以 sys.modules['hack'] = sys.modules['__main__'],但那行不通;模块本身正在被更改,模块对象不能被 pickle,所以你也不能分配 copy.copy(main)

但是,TL;DR: 如果你使用 python -i -m something 这有效,如果你使用 python -i something.py.

则无效