为什么动态格式化文档字符串不起作用?在函数定义时执行是否有可接受的解决方法?
>>> DEFAULT_BAR = "moe's tavern"
>>> def foo(bar=DEFAULT_BAR):
... """
... hello this is the docstring
...
... Args:
... bar (str) the bar argument (default: {})
... """.format(DEFAULT_BAR)
...
>>> foo.__doc__
>>> foo.__doc__ is None
True
我尝试使用old-skool样式的%s格式,但也没有用。
答案 0 :(得分:8)
您的字符串需要调用函数,但在创建函数时不会执行函数体。
正确的文档字符串不是执行,它只是从解析后的源代码中获取并附加到函数对象,没有为此执行任何代码。 Python将docstring存储为代码对象中的第一个常量值:
>>> def f():
... """docstring"""
... pass
...
>>> f.__code__.co_consts
('docstring', None)
在构造新函数时将代码对象传递给函数类型(参见PyFunction_New()
function)。
请参阅Function definitions reference documentation:
函数定义不执行函数体;只有在调用函数时才会执行此操作。 [3]
[...]
[3]作为函数体中第一个语句出现的字符串文字被转换为函数的
__doc__
属性,因此转换为函数的文档字符串。
您的定义是有效的;在函数体的顶部没有独立的字符串文字。您的字符串文字是函数本身的一部分,并且仅在调用函数时执行(并且在您不存储该结果时将结果丢弃)。
请注意,函数对象上的__doc__
属性是可写的;您可以在创建函数后始终应用变量:
>>> DEFAULT_BAR = "moe's tavern"
>>> def foo(bar=DEFAULT_BAR):
... """
... hello this is the docstring
...
... Args:
... bar (str) the bar argument (default: {})
... """
...
>>> foo.__doc__ = foo.__doc__.format(DEFAULT_BAR)
>>> print(foo.__doc__)
hello this is the docstring
Args:
bar (str) the bar argument (default: moe's tavern)
您可以在functionobject.__globals__
和inspect.getargspec()
的帮助下在装饰器中执行此操作,但是然后在模板中使用命名插槽,以便您可以将所有内容应用为字典并让文档字符串选择插值:
from inspect import getargspec
def docstringtemplate(f):
"""Treat the docstring as a template, with access to globals and defaults"""
spec = getargspec(f)
defaults = {} if not spec.defaults else dict(zip(spec.args[-len(spec.defaults):], spec.defaults))
f.__doc__ = f.__doc__ and f.__doc__.format(**dict(f.__globals__, **defaults))
return f
演示:
>>> @docstringtemplate
... def foo(bar=DEFAULT_BAR):
... """
... hello this is the docstring
...
... Args:
... bar (str) the bar argument (default: {bar!r}, or {DEFAULT_BAR!r})
...
... """
...
>>> print(foo.__doc__)
hello this is the docstring
Args:
bar (str) the bar argument (default: "moe's tavern", or "moe's tavern")
函数关键字参数会覆盖全局变量,就像在函数中一样。
答案 1 :(得分:2)
尝试类似这样的事情(推荐给@ user2357112道具):
#!python3
def FORMAT_DOC(f):
"""Decorator to format docstring of a function. Supplies
`defaults` dictionary, positional values, and argname:value
pairs to format - use {defaults[a]} or {a} or {0} to access
the 0th default value, etc.
"""
defaults = f.__defaults__
docs = f.__doc__
if docs and defaults:
nargs = f.__code__.co_argcount
argnames = f.__code__.co_varnames[nargs-len(defaults):nargs]
argdefaults = dict(zip(argnames, defaults))
f.__doc__ = docs.format(defaults=argdefaults, *defaults, **argdefaults)
return f
@FORMAT_DOC
def f(a):
pass
@FORMAT_DOC
def f(a,b,c=1,d=2):
"""Docstring
By default, c = {} and d = {}
"""
v=a+c
w=b+d
x=w/v
return x+1
@FORMAT_DOC
def f(a=0, b="foo", c="bar"):
"""Docstring: a={0}, b={defaults[b]}, c={c}"""
pass