Skip to content
VLSI Mentor

Python Part I · Module 13 · Modules, Packages and Imports

import, from ... import, and Naming What You Borrow

Chapter 13.1 used one form of the statement, which brings in a module and leaves its contents behind the dot. There is a second form that reaches in and takes a specific name out, putting it directly into your file. Both are common, both appear in the first few lines of almost every script you will inherit, and the choice between them is not a style preference — it decides whether a reader three hundred lines down can tell where a name came from. It also decides how exposed you are to one specific failure, which produces no error and no warning at all.

Foundation15 min readPythonPart IFundamentalsModulesimport

Part I · Module 13 · Chapter 13.2 · import, from ... import, and Naming What You Borrow

1. The Two Forms

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
import math
from math import sqrt

print(math.sqrt(16))
print(sqrt(16))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
4.0
4.0

Same answer, two routes.

  • import math binds one name, math, and everything inside stays behind the dot.
  • from math import sqrt binds one name, sqrt, directly in your file. The name math is not bound at all.

The second form takes several names at once:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
from math import sqrt, floor, pi

print(sqrt(25), floor(2.9), round(pi, 4))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
5.0 2 3.1416

2. from Does Not Give You the Module

A common first assumption, and it is wrong:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
from math import sqrt

print(sqrt(16))
print(math.floor(3.7))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
4.0
NameError: name 'math' is not defined

The first line worked and the second did not. from math import sqrt brought in exactly one name, and math was not it.

If you want both, ask for both — import math and from math import sqrt can coexist, and often do.

3. What Each One Costs the Reader

Consider the same call under each form, three hundred lines into a file you did not write:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
data = json.loads(text)      # clearly from the json module
data = loads(text)           # from... where?

json.loads carries its origin at the point of use. loads does not — the reader has to scroll to the import block to find out, and if the file imports six modules they may have to check several.

That cost is zero when the name is unmistakable:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
path = Path("logs") / "axi.log"     # Path is obviously pathlib's
counts = Counter(severities)         # Counter is obviously collections'

Nobody needs the module name to know what Path or Counter is.

4. The Rule

Use from X import Y when the borrowed name is unambiguous on its own. Use import X when it is generic.

NameFormWhy
Pathfrom pathlib import Pathunmistakable
Counterfrom collections import Counterunmistakable
datetimefrom datetime import datetimeunmistakable
loads / dumpsimport jsongeneric — many things load and dump
openimport ...generic, and shadows a built-in
meanimport statisticsgeneric — could be anything

The practical test: would this name mean something to a reader who has not seen the import block? If yes, take it directly. If no, keep the module in front of it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
import json
import statistics
from pathlib import Path
from collections import Counter

severities = ["error", "info", "error"]

print(json.dumps({"n": 3}))
print(statistics.mean([2, 4, 6]))
print(Path("logs") / "axi_smoke.log")
print(Counter(severities)["error"])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
{"n": 3}
4
logs/axi_smoke.log
2

Note the path separator: pathlib uses whatever is correct for the system the code runs on, so this line prints with a forward slash on macOS and Linux and a backslash on Windows. That is the point of the module — Chapter 13.4 returns to it.

5. The Silent Collision

from X import Y puts Y into your file, and your file may already have a Y. Nothing warns you, in either direction.

Your definition overwriting the import:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
from math import pow


def pow(a, b):
    return "my own pow"


print(pow(2, 3))
print(type(pow))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
my own pow
<class 'function'>

math.pow(2, 3) would be 8.0. The def ran after the import and took the name.

The import overwriting your definition:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
def load(x):
    return "my loader"


from json import loads as load

print(load("[1, 2]"))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
[1, 2]

Here the import came second and won. The function defined three lines earlier is simply gone.

(The as in that second example renames an import as it arrives — Chapter 13.3's subject, used here only to set up the collision.)

6. from X import *

A third form exists, brings in everything, and should almost never be written:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
from math import *

print(sqrt(16), floor(3.9), round(pi, 2))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
4.0 3 3.14

It works. The problem is what it does to Section 5: you cannot tell what arrived. math contributes dozens of names, and whether any of them collided with yours is not answerable by reading the file — the import line does not list them.

It also removes the benefit from Section 3 entirely. A reader seeing sqrt, gamma and hypot three hundred lines down has no line to check at all.

7. Reading an Inherited Import Block

The canonical three lines, decoded:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
import json
from pathlib import Path
from collections import Counter

record = {"test": "axi_smoke", "status": "PASS"}
log_path = Path("logs") / "axi_smoke.log"
severities = Counter(["error", "info", "error"])

print(json.dumps(record))
print(log_path.name, log_path.suffix)
print(severities.most_common(1))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
{"test": "axi_smoke", "status": "PASS"}
axi_smoke.log .log
[('error', 2)]
LineBindsTells you
import jsonjsonthis file reads or writes JSON
from pathlib import PathPathit builds or inspects file paths
from collections import CounterCounterit tallies something

Three lines, and before reading a single statement of logic you know the file handles structured data, touches the filesystem and counts occurrences of something. That is why the convention from Chapter 13.1 Section 8 puts them at the top: the import block is a summary somebody wrote whether they intended to or not.

8. Predict, Run, Observe

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
import math
from math import floor

# A
print("A:", math.floor(5.9), floor(5.9))

# B
print("B:", "floor" in dir(), "math" in dir())

# C
from collections import Counter
print("C:", Counter("aab")["a"])

# D
def ceil(x):
    return "mine"
from math import ceil
print("D:", ceil(1.2))

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A: 5 5
B: True True
C: 2
D: 2

A — both forms reach the same function.

B — both names are bound here, because both forms were used.

C — Counter on a string counts its characters, since a string is a collection of characters (Chapter 10.3).

D — 2, not "mine". The import ran after the def and took the name. Section 5, in four lines.

9. Exercises

Exercise 1 — both forms. Use math.sqrt and a directly imported sqrt in one file. Then remove the plain import math and say which line breaks and why.

Exercise 2 — choose the form. For each, say which form you would use and why in one sentence: (a) statistics.median (b) pathlib.Path (c) json.dumps (d) datetime.datetime (e) random.choice.

Exercise 3 — the name is gone. Write from math import sqrt and then try to use math.pi. Record the error and explain which name was never bound.

Exercise 4 — collide, twice. Reproduce both directions of Section 5 — your definition winning, and the import winning. Say what decides the winner in one sentence.

Exercise 5 — make it safe. Take the collision where the import won and fix it two ways: by changing the form, and by renaming. Say which you prefer.

Exercise 6 — star import. Use from math import * and then check whether pi, e and tau are all available. Say what a reader of this file cannot determine.

Exercise 7 — decode a block. For a file starting with import csv, import statistics and from pathlib import Path, write one sentence predicting what the file does.

Exercise 8 — write the block. A script reads a JSON results file, counts severities, computes a mean runtime and writes a report path. Write its four import lines, choosing the form for each.

10. Summary

  • import X binds the module's name; everything stays behind the dot.
  • from X import Y binds Y directly and does not bind X.
  • Both can be used together, and often are.
  • The dotted form carries its origin at every use site; the direct form does not.
  • Use from when the name is unambiguous — Path, Counter, datetime. Use import X when it is generic — loads, mean, open.
  • The test is whether the name means something to a reader who has not seen the import block.
  • from X import Y can collide with your own names, silently, in both directions. Whichever binding runs last wins — Chapter 2.3's rule, unchanged.
  • import X cannot collide that way, which makes it the safer default.
  • from X import * makes collisions undetectable by reading. Meet it in old code; do not write it.
  • The import block is the file's dependency summary, and reading it tells you a great deal before any logic.

The next chapter covers the one piece of import syntax this chapter borrowed without explaining.

Where this fits

Part of the Python curriculum.