将父类docstring继承为doc属性

2024-05-14 22:01:44 发布

您现在位置:Python中文网/ 问答频道 /正文

有一个关于Inherit docstrings in Python class inheritance的问题,但是那里的答案涉及方法docstring。

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

很可能sphinx和其他工具为我做了正确的事情并处理docstring继承,但是django rest framework会查看(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"

我试过像super(SubClassWithoutDocstring, self).__doc__这样的方法,但也只得到了None


Tags: 方法restapidoc属性frameworkpassprints
3条回答

在这种特殊情况下,您还可以通过重写.get_name()方法来重写REST框架如何确定要用于端点的名称。

如果您采用这种方法,您可能会发现自己想要为视图定义一组基类,并使用一个简单的mixin类覆盖所有基类视图上的方法。

例如:

class GetNameMixin(object):
    def get_name(self):
        # Your docstring-or-ancestor-docstring code here

class ListAPIView(GetNameMixin, generics.ListAPIView):
    pass

class RetrieveAPIView(GetNameMixin, generics.RetrieveAPIView):
    pass

还请注意,get_name方法被认为是私有的,并且可能在将来的某个时间点发生更改,因此在升级时,您需要在发行说明上保持标签,以查看其中的任何更改。

最简单的方法是将其指定为类变量:

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

class SubClassWithoutDoctring(ParentWithDocstring):
    __doc__ = ParentWithDocstring.__doc__

parent = ParentWithDocstring()
print parent.__doc__  # Prints "Parent docstring".
subclass = SubClassWithoutDoctring()
assert subclass.__doc__ == parent.__doc__

很不幸,这是手动的,但很简单。顺便说一句,虽然字符串格式不像通常那样工作,但它使用相同的方法:

class A(object):
    _validTypes = (str, int)
    __doc__ = """A accepts the following types: %s""" % str(_validTypes)

A accepts the following types: (<type 'str'>, <type 'int'>)

由于无法将新的__doc__docstring赋给类(至少在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)

是的,我们会跳过一两个额外的圈,但是上面的元类会找到正确的__doc__,不管您的继承图如何复杂。

用法:

>>> class ParentWithDocstring(object):
...     """Parent docstring"""
... 
>>> class SubClassWithoutDocstring(ParentWithDocstring):
...     __metaclass__ = inheritdocstring
... 
>>> SubClassWithoutDocstring.__doc__
'Parent docstring'

另一种方法是将__init__中的__doc__设置为实例变量:

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

那么至少你的实例有一个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'

从Python 3.3(它修复了issue 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

因此可以应用于:

>>> @inheritdocstring
... class SubClassWithoutDocstring(ParentWithDocstring):
...     pass
... 
>>> SubClassWithoutDocstring.__doc__
'Parent docstring'

相关问题 更多 >

    热门问题