2010-01-08 327 views
70

我想在Python中做一些類繼承。我希望每個類和繼承的類都有良好的文檔。所以我覺得對於繼承類,我想它想:繼承Python類繼承docstrings

  • 繼承基類的文檔字符串
  • 可能追加額外的相關文檔,文檔字符串

是否有任何(可能或優雅pythonic)在類繼承情況下做這種類型的文檔字符串操作的方式?如何多重繼承?

回答

32

你不是唯一的!前段時間有關於comp.lang.python的討論,並創建了一個配方。檢查出來here

""" 
doc_inherit decorator 

Usage: 

class Foo(object): 
    def foo(self): 
     "Frobber" 
     pass 

class Bar(Foo): 
    @doc_inherit 
    def foo(self): 
     pass 

Now, Bar.foo.__doc__ == Bar().foo.__doc__ == Foo.foo.__doc__ == "Frobber" 
""" 

from functools import wraps 

class DocInherit(object): 
    """ 
    Docstring inheriting method descriptor 

    The class itself is also used as a decorator 
    """ 

    def __init__(self, mthd): 
     self.mthd = mthd 
     self.name = mthd.__name__ 

    def __get__(self, obj, cls): 
     if obj: 
      return self.get_with_inst(obj, cls) 
     else: 
      return self.get_no_inst(cls) 

    def get_with_inst(self, obj, cls): 

     overridden = getattr(super(cls, obj), self.name, None) 

     @wraps(self.mthd, assigned=('__name__','__module__')) 
     def f(*args, **kwargs): 
      return self.mthd(obj, *args, **kwargs) 

     return self.use_parent_doc(f, overridden) 

    def get_no_inst(self, cls): 

     for parent in cls.__mro__[1:]: 
      overridden = getattr(parent, self.name, None) 
      if overridden: break 

     @wraps(self.mthd, assigned=('__name__','__module__')) 
     def f(*args, **kwargs): 
      return self.mthd(*args, **kwargs) 

     return self.use_parent_doc(f, overridden) 

    def use_parent_doc(self, func, source): 
     if source is None: 
      raise NameError, ("Can't find '%s' in parents"%self.name) 
     func.__doc__ = source.__doc__ 
     return func 

doc_inherit = DocInherit 
+0

對於繼承父類方法的文檔字符串的方法來說,這是很整潔的。這在我認爲的許多情況下會很有用。我正在考慮更多關於整個班級的文檔字符串,我想繼承和追加。 –

+0

啊,知道了。在這種情況下,大多數文檔都已經爲你做了。 –

23

您可以輕鬆地串連文檔字符串:

class Foo(object): 
    """ 
    Foo Class. 
    This class foos around. 
    """ 
    pass 

class Bar(Foo): 
    """ 
    Bar class, children of Foo 
    Use this when you want to Bar around. 
    parent: 
    """ 
    __doc__ += Foo.__doc__ 
    pass 

然而,這是沒用的。大多數文檔生成工具(包括SphinxEpydoc)將已經拉動父文檔字符串,包括方法。所以你不必做任何事情。

+9

確實,大多數文檔工具都是這樣做的。但內置的help()函數不會。 – MarioVilas

+0

@MarioVilas:也許這是一個應該報告的錯誤? – naught101

3

不是特別優雅,但簡單而直接:

class X(object): 
    """This class has a method foo().""" 
    def foo(): pass 

class Y(X): 
    __doc__ = X.__doc__ + ' Also bar().' 
    def bar(): pass 

現在:

>>> print Y.__doc__ 
This class has a method foo(). Also bar(). 
+0

如果你想爲'Init docstring'做這個,有沒有辦法在'Y'的定義中做到這一點?我能做到的唯一方法是使用'__init __.__ doc__ = X .__ init __.__ doc__ +'另外一個參數「'在'Y'中的__init__定義之後,但這似乎與格式混亂,導致額外的增加空間。 – mgilbert

2

混合窗框可保留兩個繼承的文檔字符串語法和優選排序可以是:

class X(object): 
    """This class has a method foo().""" 
    def foo(): pass 

class Y(X): 
    """ Also bar().""" 
    __doc__ = X.__doc__ + __doc__ 
    def bar(): pass 

與Alex的一樣輸出:

>>> print Y.__doc__ 
This class has a method foo(). Also bar(). 

薄冰:與文檔字符串玩可以讓你的模塊無法使用與python -OO,期待一些:

TypeError: cannot concatenate 'str' and 'NoneType' objects 
-1

我寫custom_inherit用於處理文檔字符串繼承提供一些簡單,重量輕的工具。

它還帶有一些不錯的默認樣式,用於合併不同類型的文檔字符串(例如Numpy,Google和reST格式的文檔字符串)。你也可以很容易地提供你自己的風格。

重疊的文檔字符串部分將推遲到孩子的部分,否則它們會以很好的格式合併在一起。