Python sınıfı kalıtımdaki docstrings'i devralın


101

Python'da bazı sınıf kalıtımı yapmaya çalışıyorum. Her sınıfın ve miras alınan sınıfın iyi belgelere sahip olmasını istiyorum. Bu yüzden miras alınan sınıf için şunu istiyorum:

  • temel sınıf docstring'i miras alır
  • belki ilgili ek dokümantasyonu docstring'e ekleyebilir

Bir sınıf mirası durumunda bu tür bir doktrin manipülasyonunu yapmanın (muhtemelen zarif veya pitonik) bir yolu var mı? Çoklu mirasa ne dersiniz?


3
Cevap veremem çünkü soru maalesef kapalıydı, ancak Python 3.5 itibariyle, inspect.getdocbir docstring bulana kadar miras ağacını arayacak.
gerrit

1
Bu cevaba bakın .
gerrit

Yanıtlar:


39

Sadece sen değilsin! Bununla comp.lang.pythonilgili bir süre önce bir tartışma yapıldı ve bir tarif oluşturuldu. Buradan kontrol edin .

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

Bu, bir metodun ana sınıfın metodunun docstringini miras alması için harika. Bunun birçok durumda faydalı olacağını düşünüyorum. Miras almak ve eklemek istediğim tüm sınıf için daha çok docstring hakkında düşünüyordum.
Craig McQueen

Ah, anladım. Bu durumda, doktor neslinin çoğu bunu sizin için zaten yapıyor.
John Feminella

39

Doküman dizilerini kolayca birleştirebilirsiniz:

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

Ancak bu işe yaramaz. Çoğu belge oluşturma aracı ( Sphinx ve Epydoc dahil), yöntemler de dahil olmak üzere ana belge dizesini zaten çekecektir. Yani hiçbir şey yapmanıza gerek yok.


16
Aslında çoğu belge aracı bunu yapar. Ancak yerleşik help () işlevi bunu yapmaz.
MarioVilas

2
@MarioVilas: Belki de rapor edilmesi gereken bir hata budur?
naught101

Sphinx bunu benim için yapıyor gibi görünmüyor, belki de ebeveynim "özel" olduğu için, yani isim bir alt çizgiyle başlıyor.
Gringo Suave

6

Pek zarif değil, ama basit ve doğrudan:

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

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

Şimdi:

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

Bunu da yapmak istiyorsanız Init docstring, tanımında bunu yapmanın bir yolu var Ymı? Bunu yapabilmemin tek yolu, __init__.__doc__ = X.__init__.__doc__ + " Also another param"içindeki __init__tanımı takip etmektir , Yancak bu, biçimlendirmeyle uğraşıyor ve fazladan boşluklara neden oluyor.
mgilbert

5

Hem miras alınan belge dizgisi sözdizimini hem de tercih edilen sıralamayı koruyabilen karma bir stil şu şekilde olabilir:

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'inkiyle aynı çıktıyla:

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

İnce buz: docstring ile oynamak modülünüzü kullanılamaz hale getirebilir python -OO, biraz bekleyin :

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

5

Docstring kalıtımını ele almak için bazı basit, hafif araçlar sağlamak için custom_inherit yazdım .

Ayrıca, farklı türdeki doküman dizilerini birleştirmek için bazı güzel varsayılan stillerle birlikte gelir (örneğin, Numpy, Google ve reST formatlı dokümanlar). Kendi tarzınızı da çok kolay bir şekilde sağlayabilirsiniz.

Örtüşen docstring bölümleri alt bölüme ertelenir, aksi takdirde güzel biçimlendirmeyle birleştirilirler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.