是的,属性文档字符串是只读的。你必须新建一处房产:
这里提出的decorator能够继承方法的docstring,但不能继承属性和getter的docstring。
我曾试图天真地扩展它,但属性的文档字符串似乎是只读的。有办法继承这些吗?
import types
def fix_docs(cls):
for name, func in vars(cls).items():
if isinstance(func, (types.FunctionType, property)) and not func.__doc__:
print func, 'needs doc'
for parent in cls.__bases__:
parfunc = getattr(parent, name, None)
if parfunc and getattr(parfunc, '__doc__', None):
func.__doc__ = parfunc.__doc__
break
return cls
class X(object):
"""
some doc
"""
angle = 10
"""Not too steep."""
def please_implement(self):
"""
I have a very thorough documentation
:return:
"""
raise NotImplementedError
@property
def speed(self):
"""
Current speed in knots/hour.
:return:
"""
return 0
@speed.setter
def speed(self, value):
"""
:param value:
:return:
"""
pass
@fix_docs
class SpecialX(X):
angle = 30
def please_implement(self):
return True
@property
def speed(self):
return 10
@speed.setter
def speed(self, value):
self.sp = value
help(X.speed)
help(X.angle)
help(SpecialX.speed)
help(SpecialX.ange)
这只会让我
Traceback (most recent call last):
<function please_implement at 0x036101B0> needs doc
<property object at 0x035BE930> needs doc
File "C:Program Files (x86)JetBrainsPyCharm Community Edition 2016.2helperspydevpydevd.py", line 1556, in <module>
globals = debugger.run(setup['file'], None, None, is_module)
File "C:Program Files (x86)JetBrainsPyCharm Community Edition 2016.2helperspydevpydevd.py", line 940, in run
pydev_imports.execfile(file, globals, locals) # execute the script
File "C:/Users/RedX/.PyCharm2016.2/config/scratches/scratch.py", line 48, in <module>
class SpecialX(X):
File "C:/Users/RedX/.PyCharm2016.2/config/scratches/scratch.py", line 10, in fix_docs
func.__doc__ = parfunc.__doc__
TypeError: readonly attribute
replacement = property(fget=original.fget,
fset=original.fset,
fdel=original.fdel,
__doc__=parentprop.__doc__)
并用它替换原来的。
最好替换原始函数的docstring,然后重新生成属性以自动传递:
original.fget.__doc__ = parentprop.__doc__
replacement = property(fget=original.fget,
fset=original.fset,
fdel=original.fdel)
此版本支持多重继承,并通过使用__mro__
而不是__bases__
从库的库中复制文档。
def fix_docs(cls):
"""
This will copy all the missing documentation for methods from the parent classes.
:param type cls: class to fix up.
:return type: the fixed class.
"""
for name, func in vars(cls).items():
if isinstance(func, types.FunctionType) and not func.__doc__:
for parent in cls.__bases__:
parfunc = getattr(parent, name, None)
if parfunc and getattr(parfunc, '__doc__', None):
func.__doc__ = parfunc.__doc__
break
elif isinstance(func, property) and not func.fget.__doc__:
for parent in cls.__bases__:
parprop = getattr(parent, name, None)
if parprop and getattr(parprop.fget, '__doc__', None):
newprop = property(fget=func.fget,
fset=func.fset,
fdel=func.fdel,
parprop.fget.__doc__)
setattr(cls, name, newprop)
break
return cls
测试:
import pytest
class X(object):
def please_implement(self):
"""
I have a very thorough documentation
:return:
"""
raise NotImplementedError
@property
def speed(self):
"""
Current speed in knots/hour.
:return:
"""
return 0
@speed.setter
def speed(self, value):
"""
:param value:
:return:
"""
pass
class SpecialX(X):
def please_implement(self):
return True
@property
def speed(self):
return 10
@speed.setter
def speed(self, value):
self.sp = value
class VerySpecial(X):
def speed(self):
"""
The fastest speed in knots/hour.
:return: 100
"""
return 100
def please_implement(self):
"""
I have my own words!
:return bool: Always false.
"""
return False
def not_inherited(self):
"""
Look at all these words!
:return:
"""
class A(object):
def please_implement(self):
"""
This doc is not used because X is resolved first in the MRO.
:return:
"""
pass
class B(A):
pass
class HasNoWords(SpecialX, B):
def please_implement(self):
return True
@property
def speed(self):
return 10
@speed.setter
def speed(self, value):
self.sp = value
def test_class_does_not_inhirit_works():
fix_docs(X)
@pytest.mark.parametrize('clazz', [
SpecialX,
HasNoWords
])
def test_property_and_method_inherit(clazz):
x = fix_docs(clazz)
assert x.please_implement.__doc__ == """
I have a very thorough documentation
:return:
"""
assert x.speed.__doc__ == """
Current speed in knots/hour.
:return:
"""
def test_inherited_class_with_own_doc_is_not_overwritten():
x = fix_docs(VerySpecial)
assert x.please_implement.__doc__ == """
I have my own words!
:return bool: Always false.
"""
assert x.speed.__doc__ == """
The fastest speed in knots/hour.
:return: 100
"""