如何将变量放入 Python docstring

所以我尝试创建一个“动态”docstring,它是这样的:

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

基本上让 @param animalType的 docstring 显示 ANIMAL_TYPES所拥有的; 这样当这个变量更新时,docstring 将自动更新。

不幸的是,它似乎不起作用。有人知道是否有办法实现这一点吗?

31244 次浏览

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.

您还可以使用.__doc__定义文档字符串

For example:

>>> def f():
pass
>>> x = 1
>>> y = "docstring"


>>> f.__doc__ = "%s string %s" % (x, y)
>>> print(f.__doc__)
1 string docstring

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'

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`

I'm using Python 3.8

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