Today, I found myself in a situation where I had a few different classes inheriting from each other, e.g.:
1 2 3 4 5 6 7 8 9
Specifically, each of these classes was a test class that I was
C had different
setup methods than
A, but otherwise ran the same test. However,
nosetests -v doesn’t
print out the name of the method’s class, only the docstring, which is
of course the same for all three classes. This made it very difficult
to tell which method was actually failing.
To resolve this, I wrote a metaclass to intercept each class at creation time and rewrite its docstrings to be prefixed with the name of the class. This was probabily overkill, but I’d been itching to play around with metaclasses for a while and decided this was a semi-valid excuse.
Here’s the code:
And here’s an example of it working its magic:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
How does this work?
__new__ method is called before the class itself is
name is the name of the future class (e.g.
are the parent classes, and
attrs is a dictionary of attributes for
First (lines 32–43), we rewrite the docstrings for the functions given
attrs. This is straightforward enough. However, this isn’t
actually sufficient to rewrite the docstrings for inherited methods,
which is what my goal ultimately was. This is because inherited
methods still belong to the class they are inherited from – the
difference is that when called, the
self contains the instance of
the child class rather than the parent class.
So, to rewrite the docstrings for all methods (even inherited ones), we need to actually make a copy of the parent methods and update the docstring of the copy (lines 45–72).
This took me a while to figure out, because I was under the mistaken
impression that when the
type metaclass transformed a function into
an unbound method of a class, it was actually creating a copy of that
function which could then be modified. This is not the case. The
unbound method is more like a read-only wrapper around the
In fact, due to the way Python’s inheritance works, if
has a method
foo that is not overridden by
C will actually have an unbound
foo method. When a lookup is
performed on the attribute
foo, Python checks the hierarchy of
C reside in until it finds
foo (which is in the
Even if you override this and explicitly create an unbound method for
C (but using the same original function), it will not matter
– if you change the docstring for the function, it changes it for all
classes that inherit it, and you cannot change the unbound method
because it is read-only. Thus, it is necessary to actually copy the
function (how very un-Pythonic…) and then change the docstring of
I don’t think I could have done this by implementing the
methods of the classes themselves (rather than creating a metaclass)
either, because bound instance methods – just like unbound class
methods – have read-only docstrings. I almost certainly could have
nose to find a better way to print out my test cases, but I
thought this was an interesting problem that deserved consideration
independent of the context it is being used in.
Have any of you played with docstrings and metaclasses much? Is there a more elegant way to do this, that I missed? Or is this, in fact, one of the rare times when it legitimately is appropriate to use a metaclass?