Python 如何定义为函数/方法调用提供插值文档字符串的装饰器
我还没有足够好的装饰师来做这件事。。。是否可以定义一个decoratorlive_doc,它允许我在方法或函数调用后获得一个插入的文档字符串,并用实际参数和返回值填充Python 如何定义为函数/方法调用提供插值文档字符串的装饰器,python,decorator,Python,Decorator,我还没有足够好的装饰师来做这件事。。。是否可以定义一个decoratorlive_doc,它允许我在方法或函数调用后获得一个插入的文档字符串,并用实际参数和返回值填充 @live_doc("f was called with %d, %s and returned %d") def f(x, y): x + len(y) 在以下代码之后: f(3, "marty") d = f.doc d应该是“f被称为3,“marty”,返回8”。我宁愿在访问f.doc之前不构建字符串,但肯定需要
@live_doc("f was called with %d, %s and returned %d")
def f(x, y):
x + len(y)
在以下代码之后:
f(3, "marty")
d = f.doc
d应该是“f被称为3,“marty”,返回8”。我宁愿在访问f.doc之前不构建字符串,但肯定需要将调用args和返回值存储在某个地方这是我的代码,(我觉得写得很傻,所以我可能做了一些错误的事情,特别是在中间部分,用<代码> t>代码>):
我用过这个
相当于
func = decomaker(argA, argB, ...)(func)
我想到了这个:
#!/usr/bin/env python
def docme(func):
def wrap(*args, **kwargs):
retval = None
wrap.__doc__ = wrap.__olddoc__ + """
Last called with args: %s, %s
""" % (args, kwargs)
try:
retval = func(*args, **kwargs)
wrap.__doc__ += 'Last returned: %s' % retval
return retval
except Exception as exc:
wrap.__doc__ += 'Failed and raised: %r' % exc
raise
wrap.__doc__ = func.__doc__ + '\n\nHas not been called yet'
wrap.__name__ = func.__name__
wrap.__olddoc__ = func.__doc__
return wrap
@docme
def foo(x):
"""foo docs"""
if x == 1:
raise ValueError('baz')
return x * 2
它维护函数的文档字符串,因此您仍然可以调用help(foo)
来阅读其说明。每次调用时,它都会使用参数和结果(或引发的异常)更新该docstring:
打印文件__
富文档
还没打电话
>>>傅(2)
4.
>>>打印foo.\u文件__
富文档
最后使用args调用:(2,),{}
最后一次返回:4
>>>傅(1)
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/tmp/foo.py”,第11行,换行
retval=func(*args,**kwargs)
文件“/tmp/foo.py”,第27行,在foo中
提升值错误('baz')
ValueError:baz
>>>打印foo.\u文件__
富文档
最后使用args调用:(1,),{}
失败并引发:ValueError('baz',)
这里有一个比较通用的解决方案,可以处理原始的docstring 作为模板,并维护有关修饰函数的其他信息 (喜欢它的名字): 在首次调用
f
之前,交互式解释器中的help(f)
将为您提供:
Help on function f in module __main__:
f(*args, **kwargs)
%(name)s was called with %(signature)s and returned %(ret_val)r.
呼叫后,您将获得:
f(*args, **kwargs)
f was called with 3, 'marty' and returned 8.
或者使用更通用的功能,显示kwargs
:
@live_doc
def q(*args, **kwargs):
"""%(name)s was called with %(signature)s and returned %(ret_val)r."""
return len(args) + len(kwargs)
>>> q(1, 2, 3, a=7, b="foo")
5
>>> help(q)
q(*args, **kwargs)
q was called with 1, 2, 3, a=7, b='foo' and returned 5.
显然,您可以在wrapper
内的模板中创建想要使用的任何变量
from functools import wraps
def live_doc(func):
template = func.__doc__
@wraps(func)
def wrapper(*args, **kwargs):
ret_val = func(*args, **kwargs)
args_pretty = ", ".join(repr(a) for a in args)
kw_pretty = ", ".join("%s=%r" % (k, v) for k, v in kwargs.items())
signature = ", ".join(x for x in (args_pretty, kw_pretty) if x)
name = func.__name__
wrapper.__doc__ = template % locals()
return ret_val
return wrapper
@live_doc
def f(x, y):
"""%(name)s was called with %(signature)s and returned %(ret_val)r."""
return x + len(y)
Help on function f in module __main__:
f(*args, **kwargs)
%(name)s was called with %(signature)s and returned %(ret_val)r.
f(*args, **kwargs)
f was called with 3, 'marty' and returned 8.
@live_doc
def q(*args, **kwargs):
"""%(name)s was called with %(signature)s and returned %(ret_val)r."""
return len(args) + len(kwargs)
>>> q(1, 2, 3, a=7, b="foo")
5
>>> help(q)
q(*args, **kwargs)
q was called with 1, 2, 3, a=7, b='foo' and returned 5.