2014-03-12 33 views
3

我有一個描述符,輪流的方法插入類級別的屬性:實現它保留了文檔字符串類屬性

class classproperty(object): 

    def __init__(self, getter): 
     self.getter = getter 
     self.__doc__ = getter.__doc__ 

    def __get__(self, instance, owner): 
     return self.getter(owner) 

像這樣來使用:

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

不過,我現在可以't訪問__doc__屬性(這是邏輯的,因爲訪問A.test.__doc__將獲取str__doc__,因爲A.test已經返回​​。

我的最終目標是我的文檔字符串將出現在獅身人面像中,因此以任何其他方式檢索文檔字符串比通過訪問屬性__doc__屬性是不可行的。我發現自己想知道這是否有可能。

我知道property通過在沒有實例的情況下調用返回類來解決此問題。但是,這顯然與我的目標相沖突。

我開始擔心這在Python中是不可能的。

:我願意拉任何特技在classproperty,只要它是穩定的(即不設置對返回值__doc__)。但是,對classproperty的用戶施加任何負擔是不可行的(即,他們應該僅使用裝飾器並且完成它)。

回答

4

的確,test是一個返回字符串的屬性。你不得不str,並給予一個__doc__屬性:

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

演示:

>>> 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' 

用途爲:

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

因爲str對象是不可改變的,你不能設置__doc__屬性在裝飾者。你必須返回一個代理對象,它完全包裝了除__doc__屬性之外的實際返回值。這變得很複雜和難看得很快。

另一種方法是在元類上放置常規的property;類的類:

class MetaClass(type): 
    @property 
    def test(cls): 
     "docstring" 
     return "Test" 

class A(object): 
    __metaclass__ = MetaClass 

現在Atest屬性和文檔字符串可以作爲MetaClass.test.__doc__被訪問,或者type(A).test.__doc__

>>> A.test 
'Test' 
>>> type(A).test 
<property object at 0x10757d158> 
>>> type(A).test.__doc__ 
'docstring' 
+2

Ooo ...在元類上的屬性(*使智力筆記*) – mgilson

+0

嗯,它似乎在這和下面的答案之間,有兩個解決方案:一個把額外的工作放在用戶上(即不容易'@ classproperty'),另一個不提供直接'__doc__')。我想我會用元類方式去。謝謝。 – javex

2

如果您通過幾個跳火圈,它可以被檢索,但由於描述符的工作方式而不是直接通過A.test.__doc__等屬性本身。

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