Python Docstrings Templated
Solution 1:
Your string requires the function to be called, but function bodies are not executed when a function is created.
A proper docstring is not executed, it is simply taken from the parsed sourcecode and attached to the function object, no code is ever executed for this. Python stores the docstring as the first constant value in a code object:
>>>deff():..."""docstring"""...pass...>>>f.__code__.co_consts
('docstring', None)
where the code object was passed to the function type when constructing a new function (see the PyFunction_New()
function).
See the Function definitions reference documentation:
The function definition does not execute the function body; this gets executed only when the function is called. [3]
[...]
[3] A string literal appearing as the first statement in the function body is transformed into the function’s
__doc__
attribute and therefore the function’s docstring.
Your definition is otherwise valid; there is just no stand-alone string literal at the top of the function body. Your string literal is instead part of the function itself, and is only executed when the function is called (and the result discarded as you don't store that).
Note that the __doc__
attribute on a function object is writable; you can always apply variables after creating the function:
>>>DEFAULT_BAR = "moe's tavern">>>deffoo(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)
You could do that in a decorator with the help of functionobject.__globals__
and inspect.getargspec()
perhaps, but then do use named slots in the template so you can apply everything as a dictionary and have the docstring choose what to interpolate:
from inspect import getargspec
defdocstringtemplate(f):
"""Treat the docstring as a template, with access to globals and defaults"""
spec = getargspec(f)
defaults = {} ifnot spec.defaults elsedict(zip(spec.args[-len(spec.defaults):], spec.defaults))
f.__doc__ = f.__doc__ and f.__doc__.format(**dict(f.__globals__, **defaults))
return f
Demo:
>>>@docstringtemplate...deffoo(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")
Function keyword arguments override globals, as they would in the function.
Solution 2:
Try something like this (props to @user2357112 for the suggestion):
#!python3defFORMAT_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_DOCdeff(a):
pass@FORMAT_DOCdeff(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_DOCdeff(a=0, b="foo", c="bar"):
"""Docstring: a={0}, b={defaults[b]}, c={c}"""pass
Post a Comment for "Python Docstrings Templated"