将父类docstring作为__doc__属性继承

Rei*_*ees 11 python docstring django-rest-framework

关于在Python类继承中继承docstrings有一个问题,但是那里的答案涉及方法docstrings.

我的问题是如何继承父类的docstring作为__doc__属性.用例是Django rest框架根据你的视图类的docstrings在你的API的html版本中生成了很好的文档.但是当在没有docstring的类中继承基类(带有docstring)时,API不会显示docstring.

很可能sphinx和其他工具做正确的事情并为我处理docstring继承,但django rest框架查看(empty).__doc__属性.

class ParentWithDocstring(object):
    """Parent docstring"""
    pass


class SubClassWithoutDoctring(ParentWithDocstring):
    pass


parent = ParentWithDocstring()
print parent.__doc__  # Prints "Parent docstring".
subclass = SubClassWithoutDoctring()
print subclass.__doc__  # Prints "None"
Run Code Online (Sandbox Code Playgroud)

我尝试了类似的东西super(SubClassWithoutDocstring, self).__doc__,但这也只是让我了None.

Mar*_*ers 12

由于您无法将新__doc__文档字符串分配给类(至少在CPython中),因此您必须使用元类:

import inspect

def inheritdocstring(name, bases, attrs):
    if not '__doc__' in attrs:
        # create a temporary 'parent' to (greatly) simplify the MRO search
        temp = type('temporaryclass', bases, {})
        for cls in inspect.getmro(temp):
            if cls.__doc__ is not None:
                attrs['__doc__'] = cls.__doc__
                break

    return type(name, bases, attrs)
Run Code Online (Sandbox Code Playgroud)

是的,我们跳过一两个额外的箍,但是上面的元类会发现正确__doc__但是复杂的你制作你的继承图.

用法:

>>> class ParentWithDocstring(object):
...     """Parent docstring"""
... 
>>> class SubClassWithoutDocstring(ParentWithDocstring):
...     __metaclass__ = inheritdocstring
... 
>>> SubClassWithoutDocstring.__doc__
'Parent docstring'
Run Code Online (Sandbox Code Playgroud)

另一种方法是设置__doc____init__,作为一个实例变量:

def __init__(self):
    try:
        self.__doc__ = next(cls.__doc__ for cls in inspect.getmro(type(self)) if cls.__doc__ is not None)
    except StopIteration:
        pass
Run Code Online (Sandbox Code Playgroud)

那么至少你的实例有一个docstring:

>>> class SubClassWithoutDocstring(ParentWithDocstring):
...     def __init__(self):
...         try:
...             self.__doc__ = next(cls.__doc__ for cls in inspect.getmro(type(self)) if cls.__doc__ is not None)
...         except StopIteration:
...             pass
... 
>>> SubClassWithoutDocstring().__doc__
'Parent docstring'
Run Code Online (Sandbox Code Playgroud)

对于Python 3.3(其中固定的问题12773),你可以最后只是设置的__doc__自定义类的属性,这样,那么你可以使用一个类装饰器:

import inspect

def inheritdocstring(cls):
    for base in inspect.getmro(cls):
        if base.__doc__ is not None:
            cls.__doc__ = base.__doc__
            break
    return cls
Run Code Online (Sandbox Code Playgroud)

然后可以这样应用:

>>> @inheritdocstring
... class SubClassWithoutDocstring(ParentWithDocstring):
...     pass
... 
>>> SubClassWithoutDocstring.__doc__
'Parent docstring'
Run Code Online (Sandbox Code Playgroud)