Как напечатать описание справки "__main__" в Python? - PullRequest
1 голос
/ 27 апреля 2020

В случае импортированных модулей вызов help(<module_name>) в интерпретаторе выведет описание модуля; обычно это строка документации, но если модуль начинается с комментариев, он передает их как описание. В сценарии, который не импортируется (ie, что-либо с __name__, равным __main__), вызов print(__doc__) даст аналогичный результат, но только при наличии строки документации; он не будет получать комментарии, как help().

Так как я могу вызвать help() для самого скрипта и получить описание, особенно если нет правильной строки документации, а есть только комментарии?

1 Ответ

5 голосов
/ 27 апреля 2020

Вы можете использовать тот факт, что модуль доступен как 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.py и python -m so61453557 действуют здесь по-разному.

Первые вызывают pymain_run_file(), что вызывает PyRun_AnyFileExFlags(), что вызывает PyRun_SimpleFileExFlags(). Насколько я могу судить, он в основном синтезирует модуль __main__ и оценивает файл в этом контексте, используя PyRun_FileExFlags.

Последний вызывает pymain_run_module(), чей реальный лог c содержится в модуле stdlib runpy.py (_run_module_as_main).

После этого

Когда -i установлено (interactive, inspect), вызывается pymain_repl(), который может вызвать интерактивный хук, если установлен (например, завершение чтения строки и прочее), а затем вызывает PyRun_AnyFileFlags(stdin, "<stdin>", cf).

Я не знаю, что очищает __main__ после запуска файла (это может быть XDECREF() в конце PyRun_SimpleFileExFlags), но вот некоторые выводы.

  • 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__'], но это не так не работает; Сам модуль изменяется, и объекты модуля не могут быть выбраны, поэтому вы также не можете назначить copy.copy(main).

Но, TL; DR: Это работает, если вы используете python -i -m something, это не так, если вы делаете python -i something.py.

...