How to put a variable into Python docstring
Solution 1
Triple-quoted strings are one big string. Nothing is evaluated inside them. The %
part is all part of the string. You'd need to have it operating on the actual string.
def func(animalType):
"""
This is a sample function.
@param animalType: "It takes one of these animal types %(ANIMAL_TYPES)s"
""" % {'ANIMAL_TYPES': ANIMAL_TYPES}
I'm not certain this will work properly, though; docstrings are a bit magic.
This will not work; the docstring is evaluated at compile time (as the first statement in the function, given it is a string literal—once it's got the %
in it it's not just a string literal), string formatting takes place at runtime, so __doc__
will be empty:
>>> def a(): 'docstring works'
...
>>> a.__doc__
'docstring works'
>>> def b(): "formatted docstring doesn't work %s" % ':-('
...
>>> b.__doc__
>>>
If you wanted to work this way, you'd need to do func.__doc__ %= {'ANIMAL_TYPES': ANIMAL_TYPES}
after the function is defined. Be aware that this would then break on python -OO
if you didn't check that __doc__
was defined, as -OO
strips docstrings.
>>> def c(): "formatted docstring works %s"
...
>>> c.__doc__
"formatted docstring works %s"
>>> c.__doc__ %= 'after'
>>> c.__doc__
"formatted docstring works after"
This is not the standard technique anyway; the standard technique is to reference the appropriate constant: "Takes one of the animal types in ANIMAL_TYPES", or similar.
Solution 2
One way to do this would be to use a decorator. I'm not sure how I feel about this; I actually searched for commentary on this method and found this answer, which rightly notes that it could mask a design problem. But your use case seems sound to me at first glance.
In any case, here's a fairly elegant way to achieve the result you're looking for:
>>> def docstring_parameter(*sub):
... def dec(obj):
... obj.__doc__ = obj.__doc__.format(*sub)
... return obj
... return dec
...
>>> @docstring_parameter('Ocean')
... def foo():
... '''My Docstring Lies Over The {0}'''
... pass
...
>>> @docstring_parameter('Sea')
... def bar():
... '''My Docstring Lies Over The {0}'''
... pass
...
>>> @docstring_parameter('Docstring', 'Me')
... def baz():
... '''Oh Bring Back My {0} To {1}'''
... pass
...
>>> foo.__doc__
'My Docstring Lies Over The Ocean'
>>> bar.__doc__
'My Docstring Lies Over The Sea'
>>> foo.__doc__
'My Docstring Lies Over The Ocean'
>>> baz.__doc__
'Oh Bring Back My Docstring To Me'
Solution 3
You can also define a docstring using .__doc__
For example:
>>> def f():
pass
>>> x = 1
>>> y = "docstring"
>>> f.__doc__ = "%s string %s" % (x, y)
>>> print(f.__doc__)
1 string docstring
Solution 4
You could simply use cross-references in your docstring to refer to the variable.
So:
:param animalType: It takes one of these :data:`animal types<ANIMAL_TYPES>`
And in the second:
:param choice: can be one of :attr:`MY_CONST`
Jack Z
Updated on July 05, 2022Comments
-
Jack Z almost 2 years
So I'm trying to create a "dynamic" docstring which is something like this:
ANIMAL_TYPES = ["mammals", "reptiles", "other"] def func(animalType): """ This is a sample function. @param animalType: "It takes one of these animal types %s" % ANIMAL_TYPES """
to basically let the docstring for
@param animalType
show whateverANIMAL_TYPES
has; so that when this variable is updated, the docstring will be updated automatically.Unfortunately, it doesn't seem to work. Does anyone know if there is a way of achieving this?
-
Jack Z about 12 yearsThanks, Chris. Can I ask why
__doc__
will be empty though in the code you crossed out? Thanks! -
Karl Knechtel about 12 yearsThe reason it's empty is because the expression
'foo %s' % 'bar'
isn't a string literal, it's an expression that would evaluate to a string. The compiler expects a real string literal, as the first thing inside the block, to qualify as a docstring. -
Jack Z about 12 yearsI eventually went with the suggestion in the last code snippet. I tried to do "Takes one of the animal types in ANIMAL_TYPES", but it didn't work well because I'm writing the docstring for an API which will be generated by SPHINX and it wouldn't print out the content of the constant in the docs, no matter what I tried... :( So now it's like (Please see the original post. Code doesn't format very well here... )
-
taz over 9 yearsCan someone provide a SSCE clarifying how to write this into a python script? See also: sphinx-doc.org/domains.html#cross-referencing-python-objects and sphinx-doc.org/domains.html#python-roles
-
nik_m over 6 yearsA slight amendment to this answer, if I may:
def docstring_parameter(*args, **kwargs):
and thenobj.__doc__ = obj.__doc__.format(*args, **kwargs)
. Now, you can do this:@docstring_parameter('Docstring', 'Me', yeah='yeah')
and'''Oh Bring Back My {} To {}. {yeah}!'''
. Finally,print(baz.__doc__)
prints'Oh Bring Back My Docstring To Me. yeah!'
. Thank you! -
endolith over 3 yearsCan you explain in more detail how to use this?
-
HitLuca almost 3 yearsNice addition @nik_m. I would like to further improve on your solution by noting the fact that a check for
obj.__doc__ is not None
would fix an issue where no docstring is set in the function!