How to put a variable into Python docstring

PythonDocstring

Python Problem Overview


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 whatever ANIMAL_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?

Python Solutions


Solution 1 - Python

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 2 - Python

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 3 - Python

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 - Python

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`

Solution 5 - Python

I'm using Python 3.8

Simple string formatting worked for me. """This is {}""".format("StackOverflow")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJack ZView Question on Stackoverflow
Solution 1 - PythonsenderleView Answer on Stackoverflow
Solution 2 - PythonChris MorganView Answer on Stackoverflow
Solution 3 - PythonAshwini ChaudharyView Answer on Stackoverflow
Solution 4 - PythonDwayneView Answer on Stackoverflow
Solution 5 - Pythonaddno1View Answer on Stackoverflow