python oop 继承_oop-在Python中继承方法的文档字符串

oop-在Python中继承方法的文档字符串

我有一个带有文档字符串的OO层次结构,它需要与代码本身一样多的维护。 例如。,

class Swallow(object):

def airspeed(self):

"""Returns the airspeed (unladen)"""

raise NotImplementedError

class AfricanSwallow(Swallow):

def airspeed(self):

# whatever

现在,问题是_ask_arthur不继承超类方法的文档字符串。 我知道我可以使用模板方法模式来保留文档字符串,即

class Swallow(object):

def airspeed(self):

"""Returns the airspeed (unladen)"""

return self._ask_arthur()

并在每个子类中实现_ask_arthur。 但是,我想知道是否还有另一种方法来继承文档字符串,也许是我还没有发现的装饰器?

5个解决方案

23 votes

这是Paul McGuire的DocStringInheritor元类的变体。

如果子成员的文档字符串继承,则它会继承父成员的文档字符串docstring为空。

如果子类docstring为,它将继承父类docstring。空的。

它可以从以下任何类继承文档字符串任何基类的MRO,就像常规属性继承一样。

与类装饰器不同,元类是继承的,因此您只需要在某些顶级基类中设置一次元类,并且docstring继承将在整个OOP层次结构中发生。

import unittest

import sys

class DocStringInheritor(type):

"""

A variation on

http://groups.google.com/group/comp.lang.python/msg/26f7b4fcb4d66c95

by Paul McGuire

"""

def __new__(meta, name, bases, clsdict):

if not('__doc__' in clsdict and clsdict['__doc__']):

for mro_cls in (mro_cls for base in bases for mro_cls in base.mro()):

doc=mro_cls.__doc__

if doc:

clsdict['__doc__']=doc

break

for attr, attribute in clsdict.items():

if not attribute.__doc__:

for mro_cls in (mro_cls for base in bases for mro_cls in base.mro()

if hasattr(mro_cls, attr)):

doc=getattr(getattr(mro_cls,attr),'__doc__')

if doc:

if isinstance(attribute, property):

clsdict[attr] = property(attribute.fget, attribute.fset,

attribute.fdel, doc)

else:

attribute.__doc__ = doc

break

return type.__new__(meta, name, bases, clsdict)

class Test(unittest.TestCase):

def test_null(self):

class Foo(object):

def frobnicate(self): pass

class Bar(Foo, metaclass=DocStringInheritor):

pass

self.assertEqual(Bar.__doc__, object.__doc__)

self.assertEqual(Bar().__doc__, object.__doc__)

self.assertEqual(Bar.frobnicate.__doc__, None)

def test_inherit_from_parent(self):

class Foo(object):

'Foo'

def frobnicate(self):

'Frobnicate this gonk.'

class Bar(Foo, metaclass=DocStringInheritor):

pass

self.assertEqual(Foo.__doc__, 'Foo')

self.assertEqual(Foo().__doc__, 'Foo')

self.assertEqual(Bar.__doc__, 'Foo')

self.assertEqual(Bar().__doc__, 'Foo')

self.assertEqual(Bar.frobnicate.__doc__, 'Frobnicate this gonk.')

def test_inherit_from_mro(self):

class Foo(object):

'Foo'

def frobnicate(self):

'Frobnicate this gonk.'

class Bar(Foo):

pass

class Baz(Bar, metaclass=DocStringInheritor):

pass

self.assertEqual(Baz.__doc__, 'Foo')

self.assertEqual(Baz().__doc__, 'Foo')

self.assertEqual(Baz.frobnicate.__doc__, 'Frobnicate this gonk.')

def test_inherit_metaclass_(self):

class Foo(object):

'Foo'

def frobnicate(self):

'Frobnicate this gonk.'

class Bar(Foo, metaclass=DocStringInheritor):

pass

class Baz(Bar):

pass

self.assertEqual(Baz.__doc__, 'Foo')

self.assertEqual(Baz().__doc__, 'Foo')

self.assertEqual(Baz.frobnicate.__doc__, 'Frobnicate this gonk.')

def test_property(self):

class Foo(object):

@property

def frobnicate(self):

'Frobnicate this gonk.'

class Bar(Foo, metaclass=DocStringInheritor):

@property

def frobnicate(self): pass

self.assertEqual(Bar.frobnicate.__doc__, 'Frobnicate this gonk.')

if __name__ == '__main__':

sys.argv.insert(1, '--verbose')

unittest.main(argv=sys.argv)

unutbu answered 2020-01-27T02:02:29Z

22 votes

以类装饰器风格编写一个函数来为您执行复制。 在Python2.5中,您可以在创建类后直接应用它。 在更高版本中,您可以使用@decorator表示法。

这是如何做到的第一步:

import types

def fix_docs(cls):

for name, func in vars(cls).items():

if isinstance(func, types.FunctionType) 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 Animal(object):

def walk(self):

'Walk like a duck'

class Dog(Animal):

def walk(self):

pass

Dog = fix_docs(Dog)

print Dog.walk.__doc__

在较新的Python版本中,最后一部分更加简单美观:

@fix_docs

class Dog(Animal):

def walk(self):

pass

这是一项Pythonic技术,与标准库中现有工具的设计完全匹配。 例如,functools.total_ordering类装饰器向类添加缺少的丰富比较方法。 再举一个例子,functools.wraps装饰器将元数据从一个函数复制到另一个函数。

Raymond Hettinger answered 2020-01-27T02:01:51Z

13 votes

仅供参考的FYY I人员:在Python 3.5上,inspection.getdoc自动从继承层次结构中检索文档字符串。

因此,上面的响应对于Python 2很有用,或者如果您想通过合并父母和孩子的文档字符串来变得更有创造力,那么它们很有用。

我还创建了一些用于文档字符串继承的轻量级工具。 这些支持开箱即用的一些不错的默认文档字符串样式(numpy,google,reST)。 您也可以轻松使用自己的文档字符串样式

Ryan Soklaski answered 2020-01-27T02:02:59Z

4 votes

以下适应还处理属性和mixin类。 我还遇到了不得不使用func.__func__(用于“实例方法”)的情况,但我不确定为什么其他解决方案不能解决这个问题。

def inherit_docs(cls):

for name in dir(cls):

func = getattr(cls, name)

if func.__doc__:

continue

for parent in cls.mro()[1:]:

if not hasattr(parent, name):

continue

doc = getattr(parent, name).__doc__

if not doc:

continue

try:

# __doc__'s of properties are read-only.

# The work-around below wraps the property into a new property.

if isinstance(func, property):

# We don't want to introduce new properties, therefore check

# if cls owns it or search where it's coming from.

# With that approach (using dir(cls) instead of var(cls))

# we also handle the mix-in class case.

wrapped = property(func.fget, func.fset, func.fdel, doc)

clss = filter(lambda c: name in vars(c).keys() and not getattr(c, name).__doc__, cls.mro())

setattr(clss[0], name, wrapped)

else:

try:

func = func.__func__ # for instancemethod's

except:

pass

func.__doc__ = doc

except: # some __doc__'s are not writable

pass

break

return cls

letmaik answered 2020-01-27T02:03:19Z

0 votes

def fix_docs(cls):

""" copies docstrings of derived attributes (methods, properties, attrs) from parent classes."""

public_undocumented_members = {name: func for name, func in vars(cls).items()

if not name.startswith('_') and not func.__doc__}

for name, func in public_undocumented_members.iteritems():

for parent in cls.mro()[1:]:

parfunc = getattr(parent, name, None)

if parfunc and getattr(parfunc, '__doc__', None):

if isinstance(func, property):

# copy property, since its doc attribute is read-only

new_prop = property(fget=func.fget, fset=func.fset,

fdel=func.fdel, doc=parfunc.__doc__)

cls.func = new_prop

else:

func.__doc__ = parfunc.__doc__

break

return cls

marscher answered 2020-01-27T02:03:35Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值