Implementing a class property that preserves the docstring

前端 未结 2 1569
长发绾君心
长发绾君心 2021-01-19 08:09

I have a descriptor that turns a method into a property on the class level:

class classproperty(object):

    def __init__(self, getter):
        self.getter         


        
相关标签:
2条回答
  • 2021-01-19 08:29

    Indeed, test is a property returning a string. You'd have to subclass str and give that a __doc__ attribute:

    class docstring_str(str):
        def __new__(cls, v, __doc__=''):
            s = super(docstring_str, cls).__new__(cls, v)
            s.__doc__ = __doc__
            return s
    

    Demo:

    >>> class docstring_str(str):
    ...     def __new__(cls, v, __doc__=''):
    ...         s = super(docstring_str, cls).__new__(cls, v)
    ...         s.__doc__ = __doc__
    ...         return s
    ... 
    >>> s = docstring_str('Test', 'docstring')
    >>> s
    'Test'
    >>> s.__doc__
    'docstring'
    

    Use as:

    class A(object):
        @classproperty
        def test(cls):
            return docstring_str("Test", "docstring')
    

    Because str objects are immutable, you cannot set the __doc__ attribute in a decorator. You'd have to return a proxy object instead that fully wraps the actual return value except for the __doc__ attribute. This gets to be complex and ugly fast.

    The alternative is to put a regular property on the metaclass; the class's class:

    class MetaClass(type):
        @property
        def test(cls):
            "docstring"
            return "Test"
    
    class A(object):
        __metaclass__ = MetaClass
    

    Now A has a test property, and the docstring can be accessed as MetaClass.test.__doc__ or with type(A).test.__doc__:

    >>> A.test
    'Test'
    >>> type(A).test
    <property object at 0x10757d158>
    >>> type(A).test.__doc__
    'docstring'
    
    0 讨论(0)
  • 2021-01-19 08:51

    If you jump through a few hoops, it can be retrieved, but not directly through the property itself like A.test.__doc__ because of the way descriptors work.

    class classproperty(object):
        def __init__(self, getter):
            self.getter = getter
    
        def __get__(self, instance, owner):
            if instance is None:  # instance attribute accessed on class?
                return self
            return self.getter(owner)
    
    class A(object):
        @classproperty
        def test(cls):
            "test's docstring"
            return "Test"
    
    def docstring(cls, methodname):
        return getattr(cls, methodname).getter.__doc__
    
    print docstring(A, 'test')  # -> test's docstring
    
    0 讨论(0)
提交回复
热议问题