how to inherit docstrings?

Eric Snow ericsnowcurrently at gmail.com
Fri Jun 10 19:25:28 EDT 2011


On Thu, Jun 9, 2011 at 12:22 AM, Eric Snow <ericsnowcurrently at gmail.com> wrote:
> Sometimes when using class inheritance, I want the overriding methods
> of the subclass to get the docstring of the matching method in the
> base class.  You can do this with decorators (after the class
> definition), with class decorators, and with metaclasses [1].
>
> However, I was hoping for a way to do it with just function decorators
> on the methods (no metaclass or class decorator).  I am not sure if
> this is doable.  I realize now that this is exactly the reason I got
> to thinking last week about objects being notified when they are bound
> [2].
>
> So, is there a way to do this with just decorators, or am I "stuck"
> with the metaclass/class decorator route?  (It's not all that bad :)
>

Thanks for all the feedback on this thread everyone!  I found a
solution that works pretty well, using descriptors:

    class DocFunc:

        TRIGGER = None

        def __init__(self, f):
            self.f = f

        def __get__(self, obj, cls):
            doc = self.f.__doc__
            if doc == self.TRIGGER:
                doc = self.get_doc(cls, self.f.__name__, self.TRIGGER)
            self.f.__doc__ = doc
            setattr(cls, self.f.__name__, self.f)
            return self.f

        @staticmethod
        def get_doc(cls, fname, default=TRIGGER, member=True):
            bases = cls.__mro__[:]
            if member:
                bases = bases[1:]
            for base in bases:
                func = getattr(base, fname, None)
                if not func:
                    continue
                doc = getattr(func, '__doc__', default)
                if doc == default:
                    continue
                return doc
            return default

        @staticmethod
        def inherits_docstring(f, context=None, fname=None, default=TRIGGER):
            if context is not None:
                cls, namespace = context
                fname = fname or f.__name__
                f.__doc__ = DocFunc.get_doc(cls, fname, default, False)
                return f
            return DocFunc(f)

    class X:
        def something(self):
            """some method"""

    class Y(X):
        @DocFunc.inherits_docstring
        def something(self):
            ...

This approach does not update the docstring if it changes in the base
class, but I don't need that for what I am doing.  If you want to
trigger on an empty string, instead of None, just change the TRIGGER.

-eric


> Thanks!
>
> -eric
>
>
> p.s. Am I missing something or can you really not change the docstring
> of a class?  I was thinking about the idea of inheriting class
> docstrings too.
>
>
> [1] http://code.activestate.com/recipes/577743-using-decorators-to-inherit-function-docstrings/
> [2] http://mail.python.org/pipermail/python-ideas/2011-June/010446.html
>



More information about the Python-list mailing list