aliases, multi-imports, and the `np.` you'll see everywhere
Multi-imports — and the one shape never to use
Two more shapes you'll see in any real Python file. One is helpful and common. The other is technically legal, occasionally used by AI, and should make you twitch when you see it.
Both are about pulling more than one name from a module at once.
Multi-import: comma-separated from
from math import pi, sqrt, floor
This pulls three specific names out of the math module in one
statement. Functionally identical to:
from math import pi
from math import sqrt
from math import floor
…just shorter. Cursor reaches for the multi-import form whenever it's pulling several utilities from the same module:
from typing import List, Dict, Optional, Tuple
from collections import defaultdict, Counter, OrderedDict
from datetime import datetime, timedelta, timezone
Run the editor. The single from math import pi, sqrt, floor line
makes all three names directly available, with no math. prefix.
The trade-off vs. import math is the same as last lesson's
from-import discussion: shorter call sites, but you lose the
"these came from math" signal at the call site. For two or three
names you use a lot, multi-import is cleaner. For a dozen, it can
get messy — you start wondering whether each call is from a module
or from your own file.
Star import: the one to avoid
from math import *
The asterisk means every name from this module. After this line,
all of math's public names — pi, sqrt, floor, cos, sin,
hundreds of others — are dumped into your file's namespace.
Cursor sometimes generates this when prompted with something like "give me access to everything in math". It is essentially always wrong, for two concrete reasons:
1. You can't tell where a name came from
from math import *
from numpy import *
print(sqrt(16)) # which sqrt? math's? numpy's?
Both math and numpy define sqrt. After two import * lines,
the second one silently overwrites the first. The sqrt you
called might not be the one you meant. There's no warning, no error,
just code that quietly used the wrong function — which can produce
subtly different numerical results.
2. It pollutes your namespace with names you didn't ask for
After from math import *, you have hundreds of names in scope. If
you write your own variable called pi or gamma or e, the
import either silently overrides it or gets silently overridden,
depending on order. You've made the code unreadable for anyone trying
to track which pi is in scope at any point.
The two correct alternatives
Either name what you want explicitly:
from math import pi, sqrt, floor
…or import the module and use the dot path:
import math
math.pi, math.sqrt(16), math.floor(3.7)
Both leave the source of every name visible at the call site. Both make refactoring safe. Both are what Cursor should generate.
Where AI specifically gets imports wrong (final round)
Three patterns to flag when you read AI's import block:
- Star imports. Always replace with named imports.
- Duplicate imports. Cursor sometimes writes
from os import pathandimport os.pathin the same file. Pick one. - Imports that aren't used. AI frequently imports things it
then doesn't use because earlier drafts of the script needed
them. A
pylint-style linter or your editor's "remove unused imports" command catches these. They're harmless, but they make the file noisier than it needs to be.
The rule for the import block at the top of any file: every line
should be necessary and named. No *, no aliases unless they're
conventional, no leftovers.
Run the editor. The three names from math are usable directly, no
prefix needed.