Python 动态函数docstring
我想编写一个具有动态创建的docstring的python函数。本质上,对于函数Python 动态函数docstring,python,Python,我想编写一个具有动态创建的docstring的python函数。本质上,对于函数func()而言,我希望func.\uuuu doc\uuuu是一个描述符,用于调用自定义\uuu get\uuuu函数,根据请求创建docstring。然后help(func)应返回动态生成的docstring 这里的上下文是编写一个python包,将大量命令行工具包装在现有的分析包中。每个工具都成为一个命名类似的模块函数(通过函数工厂创建并插入到模块名称空间中),函数文档和接口参数通过分析包动态生成。为什么不编写
func()
而言,我希望func.\uuuu doc\uuuu
是一个描述符,用于调用自定义\uuu get\uuuu
函数,根据请求创建docstring。然后help(func)
应返回动态生成的docstring
这里的上下文是编写一个python包,将大量命令行工具包装在现有的分析包中。每个工具都成为一个命名类似的模块函数(通过函数工厂创建并插入到模块名称空间中),函数文档和接口参数通过分析包动态生成。为什么不编写自己的
帮助
函数,而不是搅乱函数
my_global=42
def help(func):
print('%s: my_global=%s'%(func.func_name,my_global))
def foo():
pass
help(foo)
你不能以你想做的方式做你想做的事 从您的描述来看,您似乎可以这样做:
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)
i、 e.创建函数时,预先动态创建文档字符串。
这就是为什么从一个调用到下一个调用,docstring必须是动态的原因吗
假设有,您必须将函数封装在一个类中,使用\uuuuu call\uuuu
触发操作
但即使这样,你也有问题。当调用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属性放在元类上而不是类本身上,可以使其工作
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__
为了同样的事情。\uuu doc\uu
属性位于\u ToolWrapper
类中,需要它来捕获后一种情况。(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
,以从在Python 3.7中工作的\uuuu doc\uuuu
对象获取文本。一个更健壮的解决方案将实现其他str
方法,以便让我们的duck继续像duck一样工作,即使help
方法发生变化。还请注意,我们的mydoc
类派生自str
,这是因为help
,有点非典型,通过断言isinstance(thing.\uu doc\uuuuu,str)
来强制输入。与所有解决方案一样,这有点粗糙,但这是否是一个问题在很大程度上取决于整个项目的要求。我怀疑这是可能的,因为您甚至不能对函数类型进行子类化,更不用说以某种方式使def
生成您自己类型的对象。我想动态地这样做,因为在分析包中可以为不同的工具设置参数值,并且这些参数会被记住。我希望函数docstring显示该工具的当前参数设置。因此,当你请求“帮助(wrapped_tool)”时,它需要实时查询分析包并创建文档字符串。我还不能评论其他人的帖子(新手等),但我想说,重载help()不是一个很好的解决方案,因为你不能保证在任何地方都可以使用help()将调用。将使用您的版本而不是默认版本。根据我的经验,依赖这种猴子补丁会在以后出现意外的用例时(例如新的文档工具、使用“增强”ipython的用户或IDE中的GUI帮助等)导致难以调试的问题。很好,这就成功了。前两个代码示例正是我在发布问题之前编写的。我同意重载帮助不是一个好主意。只要对猴子补丁说不就行了。我同意@Ian的观点,help
builtin的重载不是一个好主意,因为你永远不知道它将如何在其他地方使用。但是,可能会有一个改进的实现,它会在自定义实现和默认实现之间包装一个切换。这是一个糟糕的做法,不要这样做。