如何实现可感知类的自定义@inherit_docs方法装饰器?
实现@inherit_docs装饰器:让子类方法自动继承父类文档字符串
功能说明
我想实现一个@inherit_docs装饰器,作用是将子类方法的__doc__属性,自动赋值为其所属类中第一个拥有同名方法的父类的__doc__。这个装饰器适用于多态场景,能确保子类方法文档字符串的一致性——虽然help()能自动识别父类文档,但没有手动添加文档的子类方法,其__doc__会直接返回None。
示例演示
父类定义
class A: def foo(self): """ Return something smart. """ return ...
使用装饰器的子类
class B(A): @inherit_docs def foo(self): # 针对B类,"smart"的结果固定为17,逻辑不同但文档依然适用 return 17
等价的手动实现
class B(A): def foo(self): """ Return something smart. """ # 针对B类,"smart"的结果固定为17,逻辑不同但文档依然适用 return 17
核心问题
- 装饰器
@inherit_docs如何知晓它所装饰的方法属于哪个类(比如示例中的B)? - 类尚未创建完成时,装饰器无法获取类的父类等相关信息,该如何处理?
我尝试过用元类实现,但这会限制装饰器只能用于特定元类的子类;也考虑过在方法调用时处理,但这无法解决B.foo.__doc__或help(B.foo)的显示需求。
可行实现方案
这个装饰器完全可以实现,利用Python 3.6+支持的__set_name__方法(函数/方法被绑定到类属性时自动触发)就能解决核心问题:
def inherit_docs(func): def __set_name__(self, owner, name): # 遍历类的MRO(方法解析顺序),跳过自身类 for base in owner.__mro__[1:]: if hasattr(base, name): parent_method = getattr(base, name) if parent_method.__doc__ is not None: func.__doc__ = parent_method.__doc__ break # 调用原函数的__set_name__(如果有的话) if hasattr(func, '__set_name__'): func.__set_name__(self, owner, name) func.__set_name__ = __set_name__ return func
实现原理
- 装饰器给目标方法添加了一个自定义的
__set_name__方法。 - 当类定义完成,方法被绑定到类的属性时,Python会自动调用
__set_name__,此时我们能拿到:owner:方法所属的类(比如B)name:方法的名称(比如foo)
- 通过
owner.__mro__遍历类的继承链,跳过自身类(owner.__mro__[1:]),找到第一个拥有同名方法且文档字符串非空的父类方法。 - 将父类方法的
__doc__赋值给当前方法的__doc__,完成文档继承。
验证效果
使用上述装饰器后,执行print(B.foo.__doc__)会输出:
Return something smart.
和手动添加文档字符串的效果完全一致,同时help(B.foo)也能正常显示继承的文档。
补充说明
- 该方案无需元类,不会限制子类的元类选择,灵活性更高。
- 仅在类创建时执行一次文档继承逻辑,不会影响方法的调用性能。
- 如果父类链中没有找到同名方法或所有同名方法都无文档,当前方法的
__doc__会保持原有值(如果有的话)。
内容的提问来源于stack exchange,提问作者Vedran Šego
相关产品推荐
相关产品推荐

