Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Override a method but inherit the docstring
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Shai  
View profile  
 More options Jul 23 2009, 7:51 pm
Newsgroups: comp.lang.python
From: Shai <s...@platonix.com>
Date: Thu, 23 Jul 2009 16:51:43 -0700 (PDT)
Local: Thurs, Jul 23 2009 7:51 pm
Subject: Re: Override a method but inherit the docstring
On Jul 17, 10:52 am, Steven D'Aprano <st...@REMOVE-THIS-

cybersource.com.au> wrote:

> When the decorator is called, the function object is just a function
> object, not a method, so there is no concept of "what class it is
> destined for".

... which points to the better solution: use a descriptor. With the
doc_inherit decorator defined below, one may write

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

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

and it appears to work. The code below is a little longish because we
need to do slightly different things when called for a class and for
an instance. But there's no need to repeat the parent name, no need
to look into namespaces (which, as you said, is probably messy and
fragile), and it seems pretty readable, too.

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

Combining docstrings (as suggested by Jean-Paul Calderone), and
taking proper care of classmethods and staticmethods, are left
as an exercise to the reader.

Have fun,
Shai.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.