由於無法分配新__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)
是的,我們通過一個額外的箍或兩跳,但上面的元類將找到正確的__doc__
,然而令你費解的是你的繼承圖。
用法:
>>> class ParentWithDocstring(object):
... """Parent docstring"""
...
>>> class SubClassWithoutDocstring(ParentWithDocstring):
... __metaclass__ = inheritdocstring
...
>>> SubClassWithoutDocstring.__doc__
'Parent docstring'
另一種方法是設置__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
然後至少您的實例具有一個文檔字符串:
>>> 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'
我只是從我記得有關的討論,我曾就Python的這個補充。它沒有默認繼承文檔字符串,因爲它被認爲是因爲Python無法知道文檔字符串是否會有意義(儘管繼承應該足以意味着程序員與正常的OOP保持一致,不會完全改變對象),人們認爲這種情況下,文檔是空白的將不太引人注目。在父類是ABC的情況下,它變得更加複雜...... –
在3.3中'__doc__'' getset_descriptor'現在可寫入堆類型。在它只定義了一個'getter'之前;現在它有'setter' ['type_set_doc'](http://hg.python.org/cpython/file/bd8afb90ebf2/Objects/typeobject.c#l632)。 'check_set_special_type_attr'防止刪除'__doc__'。 – eryksun
@eryksun:確認;這是一個姍姍來遲的修復!只復活了我原始的類裝飾器創意,僅適用於Python 3.3。 –