On Jul 16, 8:01 pm, 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. > > 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 newClassDict[attributeName] = attribute return type.__new__(meta, classname, bases, newClassDict) 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 -- http://mail.python.org/mailman/listinfo/python-list