【问题标题】:Inherit property getter documentation继承属性 getter 文档
【发布时间】:2016-07-26 22:34:37
【问题描述】:

提议的装饰器here 能够继承方法的文档字符串,但不能继承属性和getter。

我试图天真地扩展它,但似乎属性的文档字符串是只读的。有没有办法继承这些?

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)\JetBrains\PyCharm Community Edition 2016.2\helpers\pydev\pydevd.py", line 1556, in <module>
    globals = debugger.run(setup['file'], None, None, is_module)
  File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 2016.2\helpers\pydev\pydevd.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

【问题讨论】:

    标签: python python-decorators


    【解决方案1】:

    是的,属性文档字符串是只读的。您必须创建一个新属性:

    replacement = property(fget=original.fget,
                           fset=original.fset,
                           fdel=original.fdel,
                           __doc__=parentprop.__doc__)
    

    并用那个替换原来的。

    替换原始函数的文档字符串可能会稍微好一些,然后重新生成属性以自动传递它:

    original.fget.__doc__ = parentprop.__doc__
    replacement = property(fget=original.fget,
                           fset=original.fset,
                           fdel=original.fdel)
    

    【讨论】:

    • 你能看看我的回答中的建议吗?
    • @RedX:替换属性后你可能想break,但除此之外,它看起来还不错。
    【解决方案2】:

    此版本支持多重继承,并通过使用 __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
            """
    

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 2014-02-03
      • 2012-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-08
      • 2012-08-15
      相关资源
      最近更新 更多