A data descriptor for __doc__

In Python, suppose you want to implement a class which has a dynamically generated docstring. The easiest way to do this would be to use the @property decorator for the __doc__ attribute. (You also need your class to be a “new-style” class, i.e., inherit from object). For example:

class A(object):
    """Docstring for class."""
    def __init__(self, x):
        self.x = x
    @property
    def __doc__(self):
        return "My value of x is %s." % self.x

This gives the desired result:

>>> a = A(10)
>>> print(a.__doc__)
My value of x is 10.

But hides the docstring for the class A:

>>> A.__doc__
<property at 0x2083db8>

Read on to see how we can fix this.

To fix this, we can implement a custom class implementing the descriptor protocol. The default property descriptor behaves as:

class Property(object):
    ...
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError, "unreadable attribute"
        return self.fget(obj)

Here we see that if `obj is None`, that is, if we attempt to access `__doc__` on the class itself the property descriptor returns itself. To solve our problem we can instead return a string, perhaps something like:

class DocstringProperty(object):
    def __init__(self, fget, class_doc):
        self.fget = fget
        self.class_doc = class_doc
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self.class_doc
        else:
            return self.fget(obj)

I’ve provided a fuller implementation and a function decorator in gist #4041015.

For example:

>>> class A(object):
...     """Main docstring"""
...     def __init__(self, x):
...         self.x = x
...     @docstring_property(__doc__)
...     def __doc__(self):
...         return "My value of x is %s." % self.x
>>> A.__doc__
'Main docstring'
>>> a = A(10)
>>> print(a.__doc__)
My value of x is 10.
About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s