动态函数docstring

时间:2010-04-22 19:36:10

标签: python

我想编写一个具有动态创建的文档字符串的python函数。本质上对于函数func()我希望func.__doc__是一个调用自定义__get__函数的描述符,根据请求创建文档字符串。然后help(func)应该返回动态生成的文档字符串。

这里的上下文是在现有的分析包中编写一个包含大量命令行工具的python包。每个工具都成为一个类似命名的模块函数(通过函数工厂创建并插入到模块命名空间中),通过分析包动态生成函数文档和接口参数。

3 个答案:

答案 0 :(得分:11)

你不能按照你想要的方式做你想做的事。

根据您的描述,您似乎可以这样做:

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)

即。在创建函数时,请事先创建文档字符串。 这是为什么docstring从一个__doc__到下一个调用必须是动态的?

假设存在,则必须使用__call__触发操作,将您的功能包装在一个类中。

但即便如此,你也遇到了问题。当调用help()来查找docstring时,会在类而不是实例上调用它,所以这样的事情:

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属性放在元类而不是类本身

来使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__

同样的事情。 <{1}}属性位于__doc__类中,需要捕获后一种情况。

答案 1 :(得分:0)

为什么不编写自己的help函数?

而不是弄乱函数
my_global=42

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

def foo():
    pass

help(foo)

答案 2 :(得分:0)

(Python 3解决方案)

您可以利用Python的duck类型来实现动态字符串:

import time

def fn():
    pass

class mydoc( str ):
    def expandtabs( self, *args, **kwargs ):
        return "this is a dynamic strting created on {}".format( time.asctime() ).expandtabs( *args, **kwargs )

fn.__doc__ = mydoc()

help( fn )

注意事项: 假设help函数正在调用.expandtabs以从__doc__对象获取文本,该对象在Python 3.7中有效。更加健壮的解决方案将实现其他str方法,以便即使help方法发生更改,我们的鸭子也可以像鸭子一样继续工作。还要注意,我们的mydoc类是从str派生的,这是因为help在某种程度上是非典型的,它通过断言isinstance(thing.__doc__, str)来强制强类型化。像所有解决方案一样,这有点棘手,但是是否存在问题很大程度上取决于整个项目的需求。