Inheriting methods but over-riding docstrings

Alf P. Steinbach alfps at start.no
Sun Jan 17 19:45:17 EST 2010


* Gabriel Genellina:
> En Sat, 16 Jan 2010 14:55:11 -0300, Steven D'Aprano 
> <steve at remove-this-cybersource.com.au> escribió:
> 
>> I have a series of subclasses that inherit methods from a base class, but
>> I'd like them to have their own individual docstrings. The obvious
>> solution (other than copy-and-paste) is this:
>>
>>
>> class Base(object):
>>     colour = "Blue"
>>     def parrot(self):
>>         """docstring for Base"""
>>         return "Norwegian %s" % self.colour
>>
>>
>> class SubClass(Base):
>>     colour = "Red"
>>     def parrot(self):
>>         """docstring for Subclass"""
>>         return super(Subclass, self).parrot()
>>
>>
>> but that adds an awful lot of boilerplate to my subclasses. Are there any
>> other good solutions to this problem?
> 
> Methods don't have docstrings; functions do. So one has to "clone" the 
> function to set a new docstring.
> 
> <code>
> def copy_function(fn, docstring):
>     fn = getattr(fn, "im_func", fn) # accomodate unbound methods in 2.x
>     function_type = type(lambda:0)
>     newfn = function_type(fn.__code__, fn.__globals__, fn.__name__, 
> fn.__defaults__, fn.__closure__)
>     newfn.__doc__ = docstring
>     return newfn
> 
> class Base(object):
>     colour = "Blue"
>     def parrot(self):
>         """docstring for Base"""
>         return "Norwegian %s" % self.colour
> 
> class SubClass(Base):
>     colour = "Red"
>     parrot = copy_function(Base.parrot, "docstring for Subclass")
> 
> </code>
> 
> py> x = Base()
> py> print(x.parrot())
> Norwegian Blue
> py> print x.parrot.__doc__
> docstring for Base
> py> y = SubClass()
> py> print(y.parrot())
> Norwegian Red
> py> print y.parrot.__doc__
> docstring for Subclass

Since Steven says he has a series of subclasses, perhaps wrapping those function 
calls in a decorator?


<code>
def copy_function(fn, docstring):
     # Gabriel Genellina's copy_function
     fn = getattr(fn, "im_func", fn) # accomodate unbound methods in 2.x
     function_type = type(lambda:0)
     newfn = function_type(fn.__code__, fn.__globals__, fn.__name__, 
fn.__defaults__, fn.__closure__)
     newfn.__doc__ = docstring
     return newfn

def docstrings(**kwargs):
     def with_altered_docstrings(cls, kwargs=kwargs):
         for kwarg in kwargs.items():
             func_name = kwarg[0]
             docstring = kwarg[1]
             original_func = getattr(cls, func_name)
             new_func = copy_function(getattr(cls, func_name), docstring)
             setattr(cls, func_name, new_func)
             return cls
     return with_altered_docstrings


class Base(object):
     colour = "Blue"
     def parrot(self):
         """docstring for Base"""
         return "Norwegian %s" % self.colour

@docstrings( parrot = "docstring for Subclass" )
class SubClass(Base):
     colour = "Red"
</code>


This is my first decorator ever so it might be Incorect and nonIdiomatic...

Also, neither 'copy_function' nor 'docstrings' seem to work with slots.


Steven: on a personal note, earlier when I saw you (I think it was you) using 
the "Norwegian Parrot" example I thought it referred to me because that was the 
only sense I could make of it, it followed right after some discussion we had. 
Thus my impression of you or or responses in this group was colored by a false 
interpretation. But, checking, which is often a good idea!, and *which I should 
have done then*, as far as I can see the term was first used in this group in 
April 2001, <url: 
http://groups.google.com/group/comp.lang.python/browse_thread/thread/12a125ceddd401e2/c021547a1dc14a41>.

It's still a mystery to me what it refers to, though... :-)


Cheers & hth.,

- Alf



More information about the Python-list mailing list