Why you should avoid 'from module import whatever'

March 28, 2011

Every so often I get to re-learn vaguely painful lessons.

For whatever reason, Django has a distinct coding style, as expressed in things like their tutorial documentation. When I wrote my Django application recently I generally followed this style, partly because I took bits and pieces straight from the tutorial (because it was the easy approach). One part of the Django style is a heavy use of 'from module import SomeThing', or even 'from module import *', and I copied this for my own code. Everything worked fine and it certainly was convenient.

Then somewhat later I went back to the code and found myself staring at a section of it, wondering just where a particular function came from. Fortunately, context and naming made it fairly obvious that it wasn't a standard Django function, but I had to do a file search to determine whether it was from my views.py or my models.py.

(And I had it easy, since I only had two files that it could have come from.)

In a nutshell, this is why namespace-less imports are bad: they hide where names come from, stripping them of context. Context is a good thing, because us fallible humans can only hold so many things in our head; the more explicit context, the less we have to keep track of ourselves. Even partial module names helps (where you do 'from module import dog' and then use 'dog.SomeThing'); if nothing else, it tells you that this particular name doesn't come from the current file and it gives you an idea of where to start looking.

(In the best case the partial module name is both unique and distinctive, so it generally gives you the full context on the spot.)

Some people will object that specifying even a partial module name results in too much typing. My response is that this just means you need shorter names.

(Yes, coming up with good short names are hard. No one said API design was easy.)

PS: I don't particularly fault Django for this particular element of their style; it's consistent and fits their overall goals and does save a certain amount of more or less make-work.


Comments on this page:

From 87.194.56.231 at 2011-03-29 13:04:53:

Django's urls.py is the principal offender for this. All the examples have

 from django.conf.urls.defaults import *

But almost no mention that there is a side-effect in that you are also importing the default view names for handler404 and handler500.

David Buxton

Written on 28 March 2011.
« The problem with contributing documentation to projects
A realization about code complexity and clarity »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Mon Mar 28 22:12:20 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.