Динамическая функция документации - PullRequest
10 голосов
/ 22 апреля 2010

Я хотел бы написать функцию python, которая имеет динамически создаваемую строку документации. По сути, для функции func() я хочу, чтобы func.__doc__ был дескриптором, который вызывает пользовательскую функцию __get__, создающую строку документации по запросу. Тогда help(func) должен вернуть динамически генерируемую строку документации.

Контекст здесь заключается в написании пакета Python, который включает большое количество инструментов командной строки в существующий пакет анализа. Каждый инструмент становится модульной функцией с аналогичным названием (создается с помощью фабрики функций и вставляется в пространство имен модуля), а документация по функции и аргументы интерфейса динамически генерируются с помощью пакета анализа.

Ответы [ 2 ]

11 голосов
/ 23 апреля 2010

Вы не можете делать то, что вы хотите сделать, так, как вы хотите это сделать.

Из вашего описания кажется, что вы могли бы сделать что-то вроде этого:

for tool in find_tools():
    def __tool(*arg):
        validate_args(tool, args)
        return execute_tool(tool, args)
    __tool.__name__ = tool.name
    __tool.__doc__ = compile_docstring(tool)
    setattr(module, tool.name, __tool)

т.е. динамически создавайте строку документации при создании функции.Является ли причиной того, что строка документа должна быть динамической от одного вызова к __doc__ к следующему?

Предполагая, что есть, вам придется свернуть свою функцию в классе, используя __call__ длявызвать действие.

Но даже тогда у вас есть проблема.Когда help () вызывается для поиска строки документации, она вызывается для класса, а не для экземпляра, поэтому такая вещь:

class ToolWrapper(object):
    def __init__(self, tool):
        self.tool = tool 
        self.__name__ = tool.name
    def _get_doc(self):
        return compile_docstring(self.tool)
    __doc__ = property(_get_doc)
    def __call__(self, *args):
        validate_args(args)
        return execute_tool(tool, args)

не будет работать, поскольку свойства являются экземплярами, а не атрибутами класса,Вы можете заставить свойство doc работать с метаклассом, а не с самим классом

for tool in find_tools():
    # Build a custom meta-class to provide __doc__.
    class _ToolMetaclass(type):
        def _get_doc(self):
            return create_docstring(tool)
        __doc__ = property(_get_doc)

    # Build a callable class to wrap the tool.
    class _ToolWrapper(object):
        __metaclass__ = _ToolMetaclass
        def _get_doc(self):
            return create_docstring(tool)
        __doc__ = property(_get_doc)
        def __call__(self, *args):
            validate_args(tool, args)
            execute_tool(tool, args)

    # Add the tool to the module.
    setattr(module, tool.name, _ToolWrapper())

Теперь вы можете сделать

help(my_tool_name)

и получить пользовательскую строку документации или

my_tool_name.__doc__

за то же самое.Свойство __doc__ в классе _ToolWrapper необходимо для захвата последнего случая.

0 голосов
/ 23 апреля 2010

Вместо того, чтобы возиться с функцией, почему бы не написать свою собственную функцию help?

my_global=42

def help(func):
    print('%s: my_global=%s'%(func.func_name,my_global))        

def foo():
    pass

help(foo)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...