Re: [Python-ideas] inheriting docstrings
![](https://secure.gravatar.com/avatar/dd4761743695d5efd3692f2a3b35d37d.jpg?s=120&d=mm&r=g)
On Fri, Jun 10, 2011 at 7:29 AM, Dj Gilcrease <digitalxero@gmail.com> wrote:
Though I guess __basedocs__ mapping to [c.__doc__ for c in C.__mro__ if c != C] could be handy
Or: next(c.__doc__ for c in C.__mro__[1:] if c.__doc__) or None Right now you could do something like this: def get_basedoc(mro): return next(c.__doc__ for c in mro[1:] if c.__doc__) or None class Meta(type): __basedoc__ = property(lambda cls: get_basedoc(cls.__mro__)) But then instances don't get __basedoc__, since the metaclass is not in the MRO. To get it on instances you could do this: class C: __basedoc__ = property(lambda self: get_basedoc(self.__class__.__mro__)) But then getting that attribute on the class will give you the property object and not the docstring. I'm not sure of a way to resolve that. However, inheriting the docstring between classes is only part of the problem. You'll probably want to have the functions on a class also "inherit" their docstring from the first matching attribute of the bases on the MRO. In that case the function will not have enough information (the class isn't available to the function) to do the lookup. Instead, the class would have to do it. Here's an example: class BasedocMethod: def __init__(self, f, cls): self.f = f self.cls = cls def __getattribute__(self, name): if name == "__basedoc__": return object.__getattribute__(self, "__basedoc__") return getattr(f, name) @property def __basedoc__(self): for base in self.cls.__mro__: basefunc = base.__dict__.get(self.f.__name__) if not basefunc: continue return getattr(basefunc, "__doc__", None) return None class Meta(type): def __init__(cls, name, bases, namespace): for attrname, obj in namespace.items(): if isinstance(obj, FunctionType): setattr(cls, attrname, BasedocMethod(obj, cls)) Obviously not a perfect example, but hopefully demonstrates the idea. The whole point is that it would be nice to have a mechanism built in that makes it easy to inherit docstrings to functions, without necessarily implicitly inheriting them. The__basedoc__ idea works for that. My main motivation for this docstring inheritance is primarily for the case of abstract base classes. My implementations of those rarely have docstrings unique from that of the base class, nor do the methods. I can get around this now with metaclasses and class decorators, but it would be nice to have a little more help from the language. It would always be nice. :) -eric
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas
![](https://secure.gravatar.com/avatar/dd4761743695d5efd3692f2a3b35d37d.jpg?s=120&d=mm&r=g)
On Fri, Jun 10, 2011 at 12:40 PM, Eric Snow <ericsnowcurrently@gmail.com> wrote:
Right now you could do something like this:
def get_basedoc(mro): return next(c.__doc__ for c in mro[1:] if c.__doc__) or None
class Meta(type): __basedoc__ = property(lambda cls: get_basedoc(cls.__mro__))
But then instances don't get __basedoc__, since the metaclass is not in the MRO. To get it on instances you could do this:
class C: __basedoc__ = property(lambda self: get_basedoc(self.__class__.__mro__))
But then getting that attribute on the class will give you the property object and not the docstring.
I'm not sure of a way to resolve that.
Duh, someone just pointed out that you use your own descriptor instead of a property: class Basedoc: def __get__(self, obj, cls): return next(c.__doc__ for c in cls.__mro__[1:] if c.__doc__) or None class C: __basedoc__ = Basedoc() Inherit from the class or add it onto the class with a class decorator or metaclass. -eric
![](https://secure.gravatar.com/avatar/dd4761743695d5efd3692f2a3b35d37d.jpg?s=120&d=mm&r=g)
On Fri, Jun 10, 2011 at 1:04 AM, Greg Ewing <greg.ewing@canterbury.ac.nz> wrote:
Maybe the best thing would be for the inherited docstring to get put into a different property, such as __basedoc__. Then tools that examine docstrings can decide for themselves whether using inherited docstrings makes sense.
Another idea that I like, that someone suggested on python-list [1], is using the empty string to indicate that you want a docstring to be inherited. Here's an approximate implementation using a metaclass: class DocDescriptor: # as a non-data descriptor # but how to make it a data descriptor for the class? def __init__(self, docstring): self.docstring = docstring def __get__(self, obj, cls): if self.docstring != '': return self.docstring return next(c.__doc__ for c in cls.__mro__[1:] if c.__doc__) or '' class DocMethod: def __init__(self, f, cls): self.f = f self.cls = cls def __getattribute__(self, name): if name == '__doc__': return object.__getattribute__(self, '__doc__') f = object.__getattribute__(self, 'f') return getattr(f, name) @property def __doc__(self): f = object.__getattribute__(self, 'f') cls = object.__getattribute__(self, 'cls') if f.__doc__ != '': return f.__doc__ for base in cls.__mro__: basefunc = base.__dict__.get(self.f.__name__) if not basefunc: continue docstring = getattr(basefunc, '__doc__', None) if not docstring: continue return docstring return '' @__doc__.setter def __doc__(self, value): object.__getattribute__(self, 'f').__doc__ = value class Meta(type): def __init__(cls, name, bases, namespace): docstring = namespace.get('__doc__') cls.__doc__ = DocDescriptor(docstring) for attrname, obj in namespace.items(): if isinstance(obj, FunctionType): setattr(cls, attrname, DocMethod(obj, cls)) -eric [1] http://mail.python.org/pipermail/python-list/2011-June/1274123.html
![](https://secure.gravatar.com/avatar/6217deb9ff31cb986d5437d76d530c16.jpg?s=120&d=mm&r=g)
+1 from me for writable (not mutable of course) class __doc__ -1 from me for all that more or less implicit doc inheritance. Adding some decorator(s) to functools would be much better IMHO, e.g.: class MyDict(dict): @functools.basedoc(dict) def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ... or: @functools.superdocs # for methods without docstrings class MyDict(dict): def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ... Cheers. *j
![](https://secure.gravatar.com/avatar/6217deb9ff31cb986d5437d76d530c16.jpg?s=120&d=mm&r=g)
Jan Kaliszewski dixit (2011-06-11, 13:02):
+1 from me for writable (not mutable of course) class __doc__
-1 from me for all that more or less implicit doc inheritance.
Adding some decorator(s) to functools would be much better IMHO, e.g.:
class MyDict(dict):
@functools.basedoc(dict) def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ...
or:
@functools.superdocs # for methods without docstrings class MyDict(dict):
def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ...
Sorry, s/ super(dict/ super(MyDict/ of course.
![](https://secure.gravatar.com/avatar/6217deb9ff31cb986d5437d76d530c16.jpg?s=120&d=mm&r=g)
Probably better names...
class MyDict(dict):
@functools.basedoc(dict) def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ...
'docfrom' instead of 'basedoc' or maybe: 'inheritingdoc' or 'derivdoc'?
@functools.superdocs # for methods without docstrings class MyDict(dict):
def __setitem__(self, key, value): super(dict, self).__setitem__(key, value) ...
'docfromsuper' instead of 'superdocs' Cheers. *j
participants (2)
-
Eric Snow
-
Jan Kaliszewski