Wandering Thoughts archives

2008-06-23

Why I am not really fond of docstrings in Python

I wrote some nice things before about how I don't really use docstrings, but in thinking about it more I've realized that I was shading the truth. The real truth is that I don't really like using docstrings, and I've recently figured out why: docstrings don't stand out enough.

(I have to say here that I have nothing against documenting my code; I just want it to look right.)

Unless you use an editor and display environment that set docstrings off quite distinctly, docstrings look a lot like code (strange code, admittedly); there is nothing particular in their indentation or the start of the line that makes them stand out. Thus, it is sort of like reading Lisp for me: I have to pay attention to notice docstrings and make sure I am not merging docstrings and code together.

By contrast, comments have a quite visible marker in Python; when you are skimming code, it's very difficult to mistake a comment for code or miss a comment in the code. It is easy to page through a file looking only at comments (or only comments at a certain indentation level, or with a certain sort of formatting), or ignoring comments, much easier than doing the same thing with docstrings (without editor support).

(And I don't think it's an accident that common commenting methods in C do the same thing, despite it not being required. I think that people actively want comments to stand out quite distinctly, and this is probably one reason for the enduring popularity of 'start of line' comment markers in all sorts of programming languages.)

(This was crystalized by reading this entry and having the light suddenly go on about why my gut was curdling at the thought of lots of docstring usage to make my code look better, because I realized that I felt that it would actually make it look worse.)

In passing, I will note one advantage I see in docstrings being more merged into the code: it probably encourages a certain amount of terseness in function documentation. Speaking from personal experience, it's very easy to ramble on in comments, especially comments between functions, since they aren't all that distracting when I'm looking at the code.

DocstringsVsCommentsII written at 23:38:29; Add Comment

More thinking about Python's inheritance model

Here's something I've been pondering lately: why doesn't Python have an inheritance model more like C++, where (for example) your superclass's __init__ is automatically called?

There's a number of reasons, but I think that one of them is that Python lacks any concept of private class attributes and methods. When you limit what a subclass can do to a superclass, when you have private internal state that has to be maintained correctly, it's clear that you cannot let a subclass block the correct initialization (or destruction) of a parent class. So you have to call the superclass's initializer, and in fact you have to call them from the top of the inheritance tree on down, because you need to prevent the subclass from getting control before the superclass is ready for it.

(To develop this argument slightly more: it doesn't do any good to protect an instance attribute or a class method if you don't also protect the thing's dependencies, and one of the core dependencies is a correctly initialized object. Or in short: protecting the value of an instance attribute is pointless if you don't also protect the fact that it has a defined value.)

Since Python gives classes no such protection it is free to adopt a simpler model of class inheritance, because it is not giving subclasses any power that they don't already have. (And you can argue that the simpler model is also more powerful, since it allows Python subclasses to do things that would probably be impossible in C++.)

(Disclaimer: the author doesn't actually know C++, although he keeps intending to learn it.)

PythonInheritanceII written at 00:17:05; Add Comment

2008-06-08

Thinking about Python's inheritance model

I recently read an entry by someone who was surprised that Python subclasses did not automatically call their parent class's 'constructor' method, by which he meant __init__. This is a straightforward consequence of Python's inheritance model, but Python's inheritance model is slightly odd.

The straightforward way to explain Python's inheritance model is that it uses what I could call 'lookup based' or 'name based' subclassing, where what subclassing does is change what binding will be returned when you look up a given name on an instance of the (sub)class. And that's pretty much it as for what subclassing does.

(Technically subclassing has some additional effects when you use __slots__, but that's another discussion.)

The next thing to know is that all of Python's special operations, including __init__, work by normal method calls; they look up the binding for the name of the special method and then call what they get back (if anything). So in this model it makes perfect sense that there is no upcall to the parent class's __init__ method; your subclass overrode the binding of the name, so your method function gets called instead of the parent's. Doing an upcall would make __init__ a magic special operation, unlike all of the others.

(Note that multiple inheritance does not preclude magic upcalls, since there is a defined method resolution order that the upcalling could follow.)

One consequence of this simple model of subclassing is that you can fake subclassed instances by using other methods and outside people generally won't notice anything. (They can tell if they use isinstance() or the like, but most code shouldn't.)

PythonInheritance written at 23:51:29; Add Comment

By day for June 2008: 8 23; before June; after June.

Page tools: See As Normal.
Search:
Login: Password:
Atom Syndication: Recent Pages, Recent Comments.

This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.