Yesterday my colleague had some problems with updating Python documentation strings. Is __doc__ immutable for classes and methods? I decided to look into the matter.
So let's check this strange Python docstrings immutability.
We will catch an exception:
The reason could be found in Python sources.
Here is part of code from Python 2.7 sources "Objects/typeobject.c" file:
As you can see a setter function is NULL. So the problem is here.
Let's check the same for an instance of the class A.
So it is possible to change docstring for instance objects of a class, but the docstring of class remains unchanged.
To update docstring of classes it is possible to use metaclasses. Here is simple trick, that creates a copy of class with updated docstring.
Now let's try to change docstring for methods.
But exception will be caught again:
AttributeError: attribute '__doc__' of 'instancemethod' objects is not writable.
The reason could be found in Python "Objects/classobject.c" sources:
As you can see a setter function is NULL again.
But it's possible to bypass this limitation, knowing that instancemethod gets docstring from its __func__ method. The __doc__ attribute of function is writeable.
what is the same as:
From Python 2.7 documentation:
"Changed in version 2.6: For Python 3 forward-compatibility, im_func is also available as __func__, and im_self as __self__."
In Python 3.3 issue 12773 was fixed, and now it's possible to set the __doc__ attribute of classes.
So now, using Python version >3.3, you can just write the next for a class A:
And no exceptions will be caught.
So let's check this strange Python docstrings immutability.
Let's take the next Python code:
class A(object): """Class A""" def foo(self): """Function foo""" pass A.__doc__ = 'A class'
AttributeError: attribute '__doc__' of 'type' objects is not writable.
The reason could be found in Python sources.
Here is part of code from Python 2.7 sources "Objects/typeobject.c" file:
static PyGetSetDef type_getsets[] = { ... {"__doc__", (getter)type_get_doc, NULL, NULL}, ... }
Let's check the same for an instance of the class A.
a = A() a.__doc__ = 'A' print a.__doc__ A print A.__doc__ Class A
To update docstring of classes it is possible to use metaclasses. Here is simple trick, that creates a copy of class with updated docstring.
class A(object): """Class A""" def foo(self): """Function foo""" print 'A.foo()' def update_class_doc(cls, new_doc): new_dict = dict(cls.__dict__) new_dict['__doc__'] = new_doc new_cls = type(cls.__name__, A.__bases__, new_dict) return new_cls A = update_class_doc(A, 'Updated docstring of class A')
print A.__doc__
Updated docstring of class A
Now let's try to change docstring for methods.
A.foo.__doc__ = 'Updated docstring of foo'
AttributeError: attribute '__doc__' of 'instancemethod' objects is not writable.
The reason could be found in Python "Objects/classobject.c" sources:
static PyGetSetDef instancemethod_getset[] = { {"__doc__", (getter)instancemethod_get_doc, NULL, NULL}, {0} };
But it's possible to bypass this limitation, knowing that instancemethod gets docstring from its __func__ method. The __doc__ attribute of function is writeable.
print A.foo.__doc__ Function foo A.foo.__func__.__doc__ = 'Updated docstring of foo' print A.foo.__doc__ Updated docstring of foo
A.foo.im_func.__doc__ = 'Updated docstring of foo 2' print A.foo.__doc__ Updated docstring of foo 2
"Changed in version 2.6: For Python 3 forward-compatibility, im_func is also available as __func__, and im_self as __self__."
In Python 3.3 issue 12773 was fixed, and now it's possible to set the __doc__ attribute of classes.
static PyGetSetDef type_getsets[] = { ... {"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL}, ... }
A.__doc__ = 'A class'