class FooGonk(object): def frobnicate(self): """ Frobnicate this gonk. """ basic_implementation(self.wobble)
class BarGonk(FooGonk): def frobnicate(self): special_implementation(self.warble)
The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding the method, the original docstring is not associated with it.
Ideally there would be a way to specify that the docstring should be inherited. The best I can come up with is::
class BarGonk(FooGonk): def frobnicate(self): special_implementation(self.warble) frobnicate.__doc__ = FooGonk.frobnicate.__doc__
but that violates DRY (the association between BarGonk and FooGonk is being repeated), puts the docstring assignment awkwardly after the end of the method instead of at the beginning where docstrings normally go, and reads poorly besides.
What is the most Pythonic, DRY-adherent, and preferably least-ugly approach to override a method, but have the same docstring on both methods?
-- \ “Why, I'd horse-whip you if I had a horse.” —Groucho Marx | `\ | _o__) | Ben Finney
On Fri, 17 Jul 2009 11:01:49 +1000, Ben Finney <ben+pyt...@benfinney.id.au> wrote: >Howdy all,
>The following is a common idiom::
> class FooGonk(object): > def frobnicate(self): > """ Frobnicate this gonk. """ > basic_implementation(self.wobble)
> class BarGonk(FooGonk): > def frobnicate(self): > special_implementation(self.warble)
>The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly >applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding >the method, the original docstring is not associated with it.
>Ideally there would be a way to specify that the docstring should be >inherited. The best I can come up with is::
>but that violates DRY (the association between BarGonk and FooGonk is >being repeated), puts the docstring assignment awkwardly after the end >of the method instead of at the beginning where docstrings normally go, >and reads poorly besides.
>What is the most Pythonic, DRY-adherent, and preferably least-ugly >approach to override a method, but have the same docstring on both >methods?
How about this?
class BarGonk(FooGonk): @inherit_docstring def frobnicate(self): special_implementation(self.warble)
The implementation of "inherit_docstring" is left as an exercise for the reader (it's not utterly trivial, I admit, as "FooGonk" will not readily be at hand, but it is still possible).
By the way, I don't think this is a particularly good idea. Presumably there is a reason your implementation is special. It would probably be better if this were reflected in the docstring somehow. Perhaps this idea is a better one:
class BarGonk(FooGonk): @append_to_docstring def frobnicate(self): """ This implementation takes the warble into consideration. """ special_implementation(self.warble)
With the result of BarGonk.frobnicate.__doc__ being set to:
Frobnicate this gonk.
This implementation takes the warble into consideration.
On Thu, Jul 16, 2009 at 9:13 PM, Jean-Paul Calderone<exar...@divmod.com> wrote: > On Fri, 17 Jul 2009 11:01:49 +1000, Ben Finney <ben+pyt...@benfinney.id.au> > wrote:
>> Howdy all,
>> The following is a common idiom::
>> class FooGonk(object): >> def frobnicate(self): >> """ Frobnicate this gonk. """ >> basic_implementation(self.wobble)
>> class BarGonk(FooGonk): >> def frobnicate(self): >> special_implementation(self.warble)
>> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly >> applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding >> the method, the original docstring is not associated with it.
>> Ideally there would be a way to specify that the docstring should be >> inherited. The best I can come up with is::
>> but that violates DRY (the association between BarGonk and FooGonk is >> being repeated), puts the docstring assignment awkwardly after the end >> of the method instead of at the beginning where docstrings normally go, >> and reads poorly besides.
>> What is the most Pythonic, DRY-adherent, and preferably least-ugly >> approach to override a method, but have the same docstring on both >> methods?
> How about this?
> class BarGonk(FooGonk): > @inherit_docstring > def frobnicate(self): > special_implementation(self.warble)
> The implementation of "inherit_docstring" is left as an exercise for the > reader (it's not utterly trivial, I admit, as "FooGonk" will not readily > be at hand, but it is still possible).
> By the way, I don't think this is a particularly good idea. Presumably > there is a reason your implementation is special. It would probably be > better if this were reflected in the docstring somehow. Perhaps this > idea is a better one:
> class BarGonk(FooGonk): > @append_to_docstring > def frobnicate(self): > """ > This implementation takes the warble into consideration. > """ > special_implementation(self.warble)
> With the result of BarGonk.frobnicate.__doc__ being set to:
> Frobnicate this gonk.
> This implementation takes the warble into consideration.
Another way is to use a metaclass. Have its __new__ method loop through all attributes and compare those with what is already defined in bases. If you find a match, copy the __doc__ attribute. The advantage here is that it will work for all methods without any additional code, not counting the "__metaclass__ = ..." line. If you define a metaclass for the base, then no modifications are required for any subclasses. I do agree, however, that the best thing to do is to write a very short explanation for what the override is for.
> class FooGonk(object): > def frobnicate(self): > """ Frobnicate this gonk. """ > basic_implementation(self.wobble)
> class BarGonk(FooGonk): > def frobnicate(self): > special_implementation(self.warble)
> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly > applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding > the method, the original docstring is not associated with it.
> Ideally there would be a way to specify that the docstring should be > inherited. The best I can come up with is::
> but that violates DRY (the association between BarGonk and FooGonk is > being repeated),
Not really. Consider the case of BarGonk being a subclass of FooGonk and BazGonk; which docstring would you wish to inherit?
> puts the docstring assignment awkwardly after the end > of the method instead of at the beginning where docstrings normally go, > and reads poorly besides.
Sounds like a job for a decorator!
(This is probably unbelievably ugly and unwise, since I don't use decorators at all often.)
def copydoc(cls): def _fn(fn): if fn.__name__ in cls.__dict__: fn.__doc__ = cls.__dict__[fn.__name__].__doc__ return fn return _fn
class BarGonk(FooGonk): @copydoc(FooGonk) def frobnicate(self): special_implementation(self.warble)
-- Rhodri James *-* Wildebeest Herder to the Masses
> class FooGonk(object): > def frobnicate(self): > """ Frobnicate this gonk. """ > basic_implementation(self.wobble)
> class BarGonk(FooGonk): > def frobnicate(self): > special_implementation(self.warble)
> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly > applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding > the method, the original docstring is not associated with it.
> What is the most Pythonic, DRY-adherent, and preferably least-ugly > approach to override a method, but have the same docstring on both > methods?
Two ideas come to mind, the decorator way and the metaclass way. I am not a guru at either, but these two examples work:
# the decorator way def inherit_docstring_from(cls): def docstring_inheriting_decorator(fn): fn.__doc__ = getattr(cls,fn.__name__).__doc__ return fn return docstring_inheriting_decorator
class FooGonk(object): def frobnicate(self): """ Frobnicate this gonk. """ basic_implementation(self.wobble)
class BarGonk(FooGonk): @inherit_docstring_from(FooGonk) def frobnicate(self): special_implementation(self.warble)
bg = BarGonk() help(bg.frobnicate)
Prints: Help on method frobnicate in module __main__:
frobnicate(self) method of __main__.BarGonk instance Frobnicate this gonk.
Using a decorator in this manner requires repeating the super class name. Perhaps there is a way to get the bases of BarGonk, but I don't think so, because at the time that the decorator is called, BarGonk is not yet fully defined.
# The metaclass way
from types import FunctionType
class DocStringInheritor(type): def __new__(meta, classname, bases, classDict): newClassDict = {} for attributeName, attribute in classDict.items(): if type(attribute) == FunctionType: # look through bases for matching function by name for baseclass in bases: if hasattr(baseclass, attributeName): basefn = getattr(baseclass,attributeName) if basefn.__doc__: attribute.__doc__ = basefn.__doc__ break
class FooGonk2(object): def frobnicate(self): """ Frobnicate this gonk. """ basic_implementation(self.wobble)
class BarGonk2(FooGonk2): __metaclass__ = DocStringInheritor def frobnicate(self): special_implementation(self.warble)
bg = BarGonk2() help(bg.frobnicate)
Prints:
Help on method frobnicate in module __main__:
frobnicate(self) method of __main__.BarGonk2 instance Frobnicate this gonk.
This metaclass will walk the list of bases until the desired superclass method is found AND if that method has a docstring and only THEN does it attach the superdocstring to the derived class method.
Please use carefully, I just did the metaclass thing by following Michael Foord's Metaclass tutorial (http://www.voidspace.org.uk/python/ articles/metaclasses.shtml), I may have missed a step or two.
Paul McGuire <pt...@austin.rr.com> writes: > Two ideas come to mind, the decorator way and the metaclass way. I am > not a guru at either, but these two examples work:
I think the decorator idea is most attractive to me, since it can be applied per method.
> Using a decorator in this manner requires repeating the super class > name. Perhaps there is a way to get the bases of BarGonk, but I don't > think so, because at the time that the decorator is called, BarGonk is > not yet fully defined.
Yes, I tried a few different ways, but within the decorator it seems the function object is quite unaware of what class it is destined for.
-- \ “We are human only to the extent that our ideas remain humane.” | `\ —_Breakfast of Champions_, Kurt Vonnegut | _o__) | Ben Finney
> class FooGonk(object): > def frobnicate(self): > """ Frobnicate this gonk. """ > basic_implementation(self.wobble)
> class BarGonk(FooGonk): > def frobnicate(self): > special_implementation(self.warble)
> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly > applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding > the method, the original docstring is not associated with it.
> Ideally there would be a way to specify that the docstring should be > inherited. The best I can come up with is::
> but that violates DRY (the association between BarGonk and FooGonk is > being repeated), puts the docstring assignment awkwardly after the end > of the method instead of at the beginning where docstrings normally go, > and reads poorly besides.
> What is the most Pythonic, DRY-adherent, and preferably least-ugly > approach to override a method, but have the same docstring on both > methods?
Just thinking aloud: Write a patch for pydoc that looks up the base-class documentation.
B.f.__doc__ will continue to return None, but
help(B.f) will show something like
No documentation available for B.f.
Help for A.f: yadda yadda
Of course that might be misleading when A.f and B.f are up to something completely different...
On Fri, 17 Jul 2009 12:58:48 +1000, Ben Finney wrote: >> Using a decorator in this manner requires repeating the super class >> name. Perhaps there is a way to get the bases of BarGonk, but I don't >> think so, because at the time that the decorator is called, BarGonk is >> not yet fully defined.
> Yes, I tried a few different ways, but within the decorator it seems the > function object is quite unaware of what class it is destined for.
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".
Peter Otten <__pete...@web.de> writes: > Just thinking aloud: Write a patch for pydoc that looks up the > base-class documentation.
That doesn't scale; I want the docstring to be discovered by the normal interface (the ‘__doc__’ attribute) by *every* tool that gathers docstrings from methods.
Also, I want to have this behaviour not for every method missing a docstring, but only for selected methods.
> Of course that might be misleading when A.f and B.f are up to > something completely different...
Exactly.
-- \ “Facts do not cease to exist because they are ignored.” —Aldous | `\ Huxley | _o__) | Ben Finney
On Fri, Jul 17, 2009 at 2:58 AM, Peter Otten<__pete...@web.de> wrote: > Ben Finney wrote:
>> Howdy all,
>> The following is a common idiom::
>> class FooGonk(object): >> def frobnicate(self): >> """ Frobnicate this gonk. """ >> basic_implementation(self.wobble)
>> class BarGonk(FooGonk): >> def frobnicate(self): >> special_implementation(self.warble)
>> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly >> applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding >> the method, the original docstring is not associated with it.
>> Ideally there would be a way to specify that the docstring should be >> inherited. The best I can come up with is::
>> but that violates DRY (the association between BarGonk and FooGonk is >> being repeated), puts the docstring assignment awkwardly after the end >> of the method instead of at the beginning where docstrings normally go, >> and reads poorly besides.
>> What is the most Pythonic, DRY-adherent, and preferably least-ugly >> approach to override a method, but have the same docstring on both >> methods?
> Just thinking aloud: Write a patch for pydoc that looks up the base-class > documentation.
> B.f.__doc__ will continue to return None, but
> help(B.f) will show something like
> No documentation available for B.f.
> Help for A.f: > yadda yadda
> Of course that might be misleading when A.f and B.f are up to something > completely different...
This should never be the case. It violates LSP and would be very confusing to readers of the code.
D'Aprano<st...@remove-this-cybersource.com.au> wrote: > On Fri, 17 Jul 2009 12:58:48 +1000, Ben Finney wrote:
>>> Using a decorator in this manner requires repeating the super class >>> name. Perhaps there is a way to get the bases of BarGonk, but I don't >>> think so, because at the time that the decorator is called, BarGonk is >>> not yet fully defined.
>> Yes, I tried a few different ways, but within the decorator it seems the >> function object is quite unaware of what class it is destined for.
> 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".
> I suppose you could try to determine what namespace you're currently when > the class is created, but that's surely going to be fragile and messy.
It isn't too bad. I got the idea to use the method's enclosing scope[1] in my decorator[2] from DecoratorTools. I am working to remove it because it make me sad, but it does work.
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
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.
"At Resolver we've found it useful to short-circuit any doubt and just refer to comments in code as 'lies'. :-)" --Michael Foord paraphrases Christian Muirhead on python-dev, 2009-03-22
> class FooGonk(object): > def frobnicate(self): > """ Frobnicate this gonk. """ > basic_implementation(self.wobble)
> class BarGonk(FooGonk): > def frobnicate(self): > special_implementation(self.warble)
> The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly > applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding > the method, the original docstring is not associated with it.
> Ideally there would be a way to specify that the docstring should be > inherited. The best I can come up with is::
> but that violates DRY (the association between BarGonk and FooGonk is > being repeated), puts the docstring assignment awkwardly after the end > of the method instead of at the beginning where docstrings normally go, > and reads poorly besides.
> What is the most Pythonic, DRY-adherent, and preferably least-ugly > approach to override a method, but have the same docstring on both > methods?
I am using epydoc and if the docstring is present only in the baseclass method, it will repeat the docstring for the child methods. So basically, there's nothing to do. I've also tried within the python interpreter, and it can perfectly solve docstring inheritance. So why would you explicitly assign docstring to child methods ?
On Jul 27, 5:05 pm, Jean-Michel Pichavant <jeanmic...@sequans.com> wrote:
> Ben Finney wrote:
> > The docstring for ‘FooGonk.frobnicate’ is, intentionally, perfectly > > applicable to the ‘BarGonk.frobnicate’ method also. Yet in overriding > > the method, the original docstring is not associated with it.
> I've also tried within the python interpreter, and it can perfectly > solve docstring inheritance. So why would you explicitly assign > docstring to child methods ?
What do you mean by "can perfectly solve docstring inheritance" ?
After the following,
class Foo(object): def foo(self): "Frobber" pass
class Bar(Foo): def foo(self): pass
help(Bar.foo) does not display "Frobber" on my interpreter.
>>> The docstring for FooGonk.frobnicate is, intentionally, perfectly >>> applicable to the BarGonk.frobnicate method also. Yet in overriding >>> the method, the original docstring is not associated with it.
>> I've also tried within the python interpreter, and it can perfectly >> solve docstring inheritance. So why would you explicitly assign >> docstring to child methods ?
> What do you mean by "can perfectly solve docstring inheritance" ?
> After the following,
> class Foo(object): > def foo(self): > "Frobber" > pass
> class Bar(Foo): > def foo(self): > pass
> help(Bar.foo) does not display "Frobber" on my interpreter.
You're right. I must have made some dumb mistake. So interpreters do not solve docstring inheritance, Epydoc does.