Kế thừa docstrings trong kế thừa lớp Python


97

Tôi đang cố gắng thực hiện một số kế thừa lớp trong Python. Tôi muốn mỗi lớp và lớp kế thừa có docstrings tốt. Vì vậy, tôi nghĩ đối với lớp kế thừa, tôi muốn nó:

  • kế thừa docstring lớp cơ sở
  • có thể thêm tài liệu bổ sung có liên quan vào docstring

Có cách nào (có thể thanh lịch hoặc lạ lùng) để thực hiện loại thao tác chuỗi doc này trong tình huống kế thừa lớp không? Làm thế nào về đa kế thừa?


2
Tôi không thể trả lời vì không may câu hỏi đã bị đóng, nhưng kể từ Python 3.5, inspect.getdocsẽ tìm kiếm cây kế thừa cho đến khi nó tìm thấy một chuỗi doc.
gerrit 19/1218

Câu trả lời:


39

Bạn không phải là người duy nhất! Đã có một cuộc thảo luận comp.lang.pythonvề điều này một thời gian trước, và một công thức đã được tạo ra. Kiểm tra nó ra ở đây .

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

Điều đó thật gọn gàng cho một phương thức kế thừa chuỗi docstring của phương thức lớp cha. Điều đó sẽ hữu ích trong nhiều trường hợp tôi nghĩ. Tôi đã suy nghĩ nhiều hơn về docstring cho cả lớp, nơi tôi muốn kế thừa và nối thêm.
Craig McQueen

Ah, gotcha. Trong trường hợp đó, hầu hết thế hệ tài liệu đã làm điều đó cho bạn.
John Feminella

36

Bạn có thể nối các docstrings một cách dễ dàng:

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

Tuy nhiên, điều đó là vô ích. Hầu hết công cụ tạo tài liệu ( bao gồm cả SphinxEpydoc ) sẽ kéo chuỗi tài liệu gốc, bao gồm cả các phương thức. Vì vậy, bạn không phải làm bất cứ điều gì.


16
Thật vậy, hầu hết các công cụ tài liệu đều làm được điều đó. Nhưng hàm help () tích hợp thì không.
MarioVilas

2
@MarioVilas: có lẽ đó là một lỗi cần được báo cáo?
naught101

Sphinx dường như không làm điều đó đối với tôi, có lẽ vì cha mẹ tôi là "riêng tư" hay còn gọi là tên bắt đầu bằng dấu gạch dưới.
Gringo Suave

6

Không đặc biệt thanh lịch, nhưng đơn giản và trực tiếp:

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

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

Hiện nay:

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

Nếu bạn cũng muốn làm điều này Init docstring, có cách nào để làm điều đó trong định nghĩa của Ykhông? Cách duy nhất tôi có thể làm là sử dụng __init__.__doc__ = X.__init__.__doc__ + " Also another param"theo __init__định nghĩa trong Ynhưng điều này dường như gây rối với định dạng, gây ra thêm khoảng cách.
mgilbert,

5

Một giai đoạn hỗn hợp có thể bảo tồn cả cú pháp docstring kế thừa và thứ tự ưu tiên có thể là:

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

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

Với đầu ra tương tự như của Alex:

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

Đá mỏng: chơi với docstring có thể khiến mô-đun của bạn không sử dụng được python -OO, mong đợi một số:

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

4

Tôi đã viết custom_inherit để cung cấp một số công cụ đơn giản, trọng lượng nhẹ để xử lý kế thừa docstring.

Nó cũng đi kèm với một số kiểu mặc định đẹp mắt để hợp nhất các loại docstrings khác nhau (ví dụ: Numpy, Google và docstrings được định dạng reST). Bạn cũng có thể cung cấp phong cách của riêng bạn rất dễ dàng.

Các phần chuỗi tài liệu chồng chéo sẽ chuyển sang phần của trẻ, nếu không, chúng được hợp nhất với nhau với định dạng đẹp.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.