สืบทอด docstrings ในการสืบทอดคลาส Python


101

ฉันกำลังพยายามสืบทอดคลาสใน Python ฉันต้องการให้แต่ละคลาสและคลาสที่สืบทอดมามี docstrings ที่ดี ดังนั้นฉันคิดว่าสำหรับคลาสที่สืบทอดฉันต้องการที่จะ:

  • สืบทอด docstring คลาสพื้นฐาน
  • อาจแนบเอกสารเพิ่มเติมที่เกี่ยวข้องเข้ากับ docstring

มีวิธีใด (ที่อาจสง่างามหรือไพโธนิก) ในการจัดการกับ docstring ประเภทนี้ในสถานการณ์การสืบทอดคลาสหรือไม่? แล้วการสืบทอดหลาย ๆ อย่างล่ะ?


3
ฉันตอบไม่ได้เพราะน่าเสียดายที่คำถามถูกปิดไป แต่ใน Python 3.5 inspect.getdocจะค้นหาแผนผังการสืบทอดจนกว่าจะพบ docstring
gerrit

1
ดูคำตอบนี้
gerrit

คำตอบ:


39

ไม่ใช่แค่คุณคนเดียว! มีการอภิปรายcomp.lang.pythonเกี่ยวกับเรื่องนี้เมื่อไม่นานมานี้และมีการสร้างสูตรอาหาร ตรวจสอบออกที่นี่

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

นั่นเป็นเรื่องที่เรียบร้อยสำหรับวิธีการสืบทอด docstring ของเมธอดคลาสแม่ นั่นจะเป็นประโยชน์ในหลาย ๆ กรณีที่ฉันคิด ฉันคิดมากขึ้นเกี่ยวกับ docstring สำหรับทั้งชั้นเรียนซึ่งฉันต้องการสืบทอดและต่อท้าย
Craig McQueen

อ่า gotcha ในกรณีนี้คนรุ่นใหม่ส่วนใหญ่ทำสิ่งนั้นให้คุณอยู่แล้ว
John Feminella

39

คุณสามารถเชื่อมต่อ docstrings ได้อย่างง่ายดาย:

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

อย่างไรก็ตามนั่นไม่มีประโยชน์ เครื่องมือสร้างเอกสารส่วนใหญ่ (รวมSphinxและEpydoc ) จะดึง docstring หลักอยู่แล้วรวมถึงวิธีการ คุณจึงไม่ต้องทำอะไร


16
เครื่องมือเอกสารส่วนใหญ่ทำเช่นนั้น แต่ฟังก์ชัน help () ในตัวไม่มี
MarioVilas

2
@MarioVilas: บางทีนั่นอาจเป็นข้อผิดพลาดที่ควรรายงาน?
naught101

ดูเหมือนว่าสฟิงซ์จะไม่ทำแบบนั้นให้ฉันอาจเป็นเพราะพ่อแม่ของฉันเป็นชื่อ "ส่วนตัว" ที่เริ่มต้นด้วยเครื่องหมายขีดล่าง
Gringo Suave

6

ไม่หรูหราเป็นพิเศษ แต่เรียบง่ายและตรงไปตรงมา:

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().

ถ้าคุณต้องการทำเช่นนี้Init docstringเช่นกันมีวิธีที่จะทำในคำจำกัดความของY? วิธีเดียวที่ฉันสามารถทำได้คือใช้การ__init__.__doc__ = X.__init__.__doc__ + " Also another param"ทำตาม__init__คำจำกัดความYแต่ดูเหมือนจะยุ่งกับการจัดรูปแบบทำให้มีช่องว่างเพิ่มเติม
mgilbert

5

Stile แบบผสมที่สามารถเก็บรักษาทั้งไวยากรณ์ docstring ที่สืบทอดมาและลำดับที่ต้องการสามารถ:

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().

น้ำแข็งบาง ๆ : การเล่นกับ docstring อาจทำให้โมดูลของคุณใช้งานไม่ได้python -OOคาดว่าจะมีบางส่วน:

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

5

ฉันเขียนcustom_inheritเพื่อจัดหาเครื่องมือง่ายๆน้ำหนักเบาสำหรับจัดการการสืบทอด docstring

นอกจากนี้ยังมาพร้อมกับสไตล์เริ่มต้นที่ดีสำหรับการรวม docstrings ประเภทต่างๆ (เช่น Numpy, Google และ docstrings ที่จัดรูปแบบ reST) คุณยังสามารถสร้างสไตล์ของคุณเองได้อย่างง่ายดาย

ส่วน docstring ที่ทับซ้อนกันจะเลื่อนไปที่ส่วนของเด็กมิฉะนั้นจะรวมเข้าด้วยกันด้วยการจัดรูปแบบที่ดี

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.