Why import star is a bad idea

When I was learning Python, I of course read the usual warnings. They told me: You can do

from something_or_other import *

but don’t do it. Importing star (asterisk, everything) is a Python Worst Practice.

Don’t “import star”!

But I was young and foolish, and my scripts were short. “How bad can it be?” I thought. So I did it anyway, and everything seemed to work out OK.

Then, like they always do, the quick-and-dirty scripts grew into programs, and then grew into a full-blown system. Before long I had a monster on my hands, and I needed a tool that would look through all of the scripts and programs in the system and do (at least) some basic error checking.

I’d heard good things about pyflakes, so I thought I’d give it a try.

It worked very nicely. It found the basic kinds of errors that I wanted it to find. And it was fast, so I could run it through a directory containing a lot of .py files and it would come out alive and grinning on the other side.

During the process, I learned that pyflakes is designed to be a bit on the quick and dirty side itself, with the quick making up for the dirty. As part of this process, it basically ignores star imports.  Oh, it warns you about the star imports.  What I means is — it doesn’t try to figure out what is imported by the star import.

And that has interesting consequences.

Normally, if your file contains an undefined name — say TARGET_LANGAGE — pyflakes will report it as an error.

But if your file includes any star imports, and your script contains an undefined name like TARGET_LANGAGE, pyflakes won’t report the undefined name as an error.

My hypothesis is that pyflakes doesn’t report TARGET_LANGAGE as undefined because it can’t tell whether TARGET_LANGAGE is truly undefined, or was pulled in by some star import.

This is perfectly understandable. There is no way that pyflakes is going to go out, try to find the something_or_other module, and analyze it to see if it contains TARGET_LANGAGE. And if it doesn’t, but contains star imports, go out and look for all of the modules that something_or_other star imports, and then analyze them. And so on, and so on, and so on. No way!

So, since pyflakes can’t tell whether TARGET_LANGAGE is (a) an undefined name or (b) pulled in via some star import, it does not report TARGET_LANGAGE as an undefined name. Basically, pyflakes ignores it.

And that seems to me to be a perfectly reasonable way to do business, not just for pyflakes but for anything short of the Super Deluxe Hyperdrive model static code analyzer.

The takeaway lesson for me was that using star imports will cripple a static code analyzer. Or at least, cripple the feature that I most want a code analyser for… to find and report undefined names.

So now I don’t use star imports anymore.

There are a variety of alternatives.  The one that I prefer is the “import x as y” feature. So I can write an import statement this way:

import   some_module_with_a_big_long_hairy_name   as    bx

 and rather than coding

x = some_module_with_a_big_long_hairy_name.vector

I can code

x = bx.vector

Works for me.

About these ads

11 thoughts on “Why import star is a bad idea

  1. I use some “standard” (jokingly, of course) abbreviations:

    import itertools as it, operator as op, functools as ft, unicodedata as ud

    I don’t think I abbreviate other stdlib modules.

  2. I always try to avoid star imports myself. I usually try to import only what I need (including functions and classes from stdlib modules and packages).

  3. I recently fixed some stuff in CVS of pychecker to deal with star imports and following what they import exactly.

    I´d be interested in having you try it out and see if it was able to catch the problems you saw that pyflakes couldn´t ?

    Feel free to drop me a line!

    T

    • I hope to have some time soon. If I do, I’ll let you know what happens.

      Thanks for this update!

  4. I’m under the impression that pylint will actually load all the modules needed for star imports. You might want to give that a try!

  5. Yeah, I would take away from it the opposite – don’t use pyflakes. It sounds “flaky.”

  6. A bug in the pyflakes module doesn’t really sound like a convincing argument to me.
    PEP8 mentions “Modules that are designed for use via from M import *”, and it’s written by Guido Van Rossum, so I think it’s safe to trust that document.
    Anyway, I wouldn’t be so categorical: there are modules where importing * just doesn’t affect readability at all “by design” (as Guido says…).
    Do you really think it’s likely that after importing * from socket you’ll want to redefine AF_INET in your namespace?

  7. I’m new to Python and the like the author have read the warnings about using import * but I was wondering if this warning extends to tkinter where even the official tutorial uses:
    from tkinter import *

    • I don’t know of anything that makes importing star less-bad for tkinter than for any other module. Personally, I usually code “import tkinter as tki” and then fully qualify everything, for example “tki.TOP”.

      Official tutorials can be wrong. When I first wrote EasyGui, the EasyGui tutorial used “from easygui import *”. That was a bad idea, and I’m slowly fixing the EasyGui tutorial so that the code examples no longer use “from easygui import *”. I expect the same is true of tkinter. That is, I suspect that originally the tkinter tutorial was written using import star. Today nobody would write it that way, but nobody has got around to systematically re-writing the tutorial.

      • That was a lot simpler than I thought it would be. Took me awhile to work out why my widgets were a mix of original and themed though.

  8. It’s kind of ridiculous for people to call this a “bug in pyflakes”. pyflakes is only “quick-and-dirty” in the sense that it’s a very simple tool, and designed to run fast. It’s really neat if some static code analysis tools can go out and cross-reference other files to get a fuller picture, but I really like what pyflakes is today and I hope it never tries to implement tricks for analyzing star imports.

    See, if pyflakes can catch something, it means you can discover it without having to go look at another source file. If pyflakes can’t catch something, a lot of other programmer’s tools (and a lot of programmers) are going to get confused by it. (In fact, python is one of very few languages with namespace rules simple and consistent enough that tools as simple as pyflakes can find any interesting bugs.) The question is: when you’re using star imports, how much are you giving up, and how much are you gaining?

    Star imports have their places. Usually they work very well in very short scripts that are importing very little besides the one big star import. A lot of tutorial code falls under that heading, and I certainly wouldn’t call them “wrong” for doing it. But I’ve never regretted using explicit imports, and I’ve never been glad I used a star import.

    All that said, if you absolutely must use “import *” in serious projects, I beg of you, at least _try_ to follow some guidelines:
    – keep it localized in very short modules with very specific purposes
    – do not use multiple star imports in the same file, or “chain” star imports
    – consider using “import X as Y” to abbreviate names instead

Comments are closed.