我有一组函数(主要是)共享参数但不同的进程。我想使用装饰器将每个参数的描述添加到函数的标题级文档字符串中。
我试图通过在appender
中合并嵌套函数来模仿this answer中找到的结构但是失败了。我也试过了functools.partial
,但有些事情稍微偏了。
我的尝试:
def appender(func, *args):
"""Appends additional parameter descriptions to func's __doc__."""
def _doc(func):
params = ''.join([defaultdocs[arg] for arg in args])
func.__doc__ += '\n' + params
return func
return _doc
defaultdocs = {
'a' :
"""
a : int, default 0
the first parameter
""",
'b' :
"""
b : int, default 1
the second parameter
"""
}
@appender('a')
def f(a):
"""Title-level docstring."""
return a
@appender('a', 'b')
def g(a, b):
"""Title-level docstring."""
return a + b
这失败了,我失败了,我相信因为传递给appender
的第一个arg被解释为func
。因此,当我查看g
的结果文档字符串时,我得到:
print(g.__doc__)
Title-level docstring.
b : int, default 1
the second parameter
因为,当我希望'a'
成为'func'
的第一个元素时,*args
被解释为print(g.__doc__)
Title-level docstring.
a : int, default 0
the first parameter
b : int, default 1
the second parameter
。我怎么能纠正这个?
期望的结果:
let gSmall, gLarge, defaultOrder =
if g1remainingNodesToMap.Count <= g2remainingNodesToMap.Count then
g1remainingNodesToMap, g2remainingNodesToMap, true
else g2remainingNodesToMap, g1remainingNodesToMap, false
答案 0 :(得分:4)
这是因为您传递的变量名实际上被捕获到func
参数中。
为了在Python中执行可调用装饰器,您需要对函数进行两次编码,使用外部函数来接受装饰器参数,使用内部函数来接受原始函数。可调用装饰器只是返回其他装饰器的高阶函数。例如:
def appender(*args): # This is called when a decorator is called,
# e. g. @appender('a', 'b')
"""Appends additional parameter descriptions to func's __doc__."""
def _doc(func): # This is called when the function is about
# to be decorated
params = ''.join([defaultdocs[arg] for arg in args])
func.__doc__ += '\n' + params
return func
return _doc
外部(appender
)函数充当新装饰器的工厂,而_doc
函数是实际的装饰器。总是以这种方式传递:
一旦Python看到了这个:
@appender('a', 'b')
def foo(): pass
......它会在幕后做这样的事情:
foo = appender('a', 'b')(foo)
......扩展到这个:
decorator = appender('a', 'b')
foo = decorator(foo)
由于Python中的作用域如何工作,每个新返回的_doc
函数实例将具有来自外部函数的自己的本地args
值。
答案 1 :(得分:1)
使用inspect.signature
收集传递的函数参数的替代解决方案。
import inspect
import textwrap
def appender(defaultdocs):
def _doc(func):
params = inspect.signature(func).parameters
params = [param.name for param in params.values()]
params = ''.join([textwrap.dedent(defaultdocs[param])
for param in params])
func.__doc__ += '\n\nParameters\n' + 10 * '=' + params
return func
return _doc
示例:
# default docstrings for parameters that are re-used often
# class implementation not a good alternative in my specific case
defaultdocs = {
'a' :
"""
a : int, default 0
the first parameter""",
'b' :
"""
b : int, default 1
the second parameter"""
}
@appender
def f(a):
"""Title-level docstring."""
return a
@appender
def g(a, b):
"""Title-level docstring."""
return a + b
这会将a
和b
的说明附加到g.__doc__
,而无需在装饰器中指定它们:
help(g)
Help on function g in module __main__:
g(a, b)
Title-level docstring.
Parameters
==========
a : int, default 0
the first parameter
b : int, default 1
the second parameter