074. From Module Import
Import specific names for concise code
074. From Module Import
Every line in his stats module starts with math. or random.. It reads like boilerplate.
# Before — math. prefix everywhere
import math
stdev = math.sqrt(variance)
scaled = math.log2(rss_mb)
floored = math.floor(percent)He discovers from math import sqrt, log2, floor:
# After — clean, no prefix needed
from math import sqrt, log2, floor
stdev = sqrt(variance)
scaled = log2(rss_mb)
floored = floor(percent)⚠️ Trap:
from math import *dumps everything into the namespace. Three weeks later, where didlogcome from? Use explicit names.
Rule: Use
from X import Ywhen Y is used heavily and the prefix clutters. Useimport mathwhen you need clarity or to avoid name collisions.
💡 Fun fact: The infamous from module import * anti-pattern was so widely abused in early Python code that PEP 328 (Python 2.4) introduced explicit relative imports partly to reduce namespace pollution. Scientific Python packages like NumPy still officially document from numpy import * for interactive sessions but forbid it in library code for exactly the reasons Aryan just discovered.
⚠️ Watch out: from math import log brings log (natural log) into scope. If you later write log = "some message" in the same file, you silently overwrite the imported function with a string. This is the namespace collision hazard that import math; math.log(...) completely avoids.
🤔 Think about it: If you write from math import sqrt at the top of a file, and someone later adds def sqrt(x): ... lower in the same file, which sqrt wins? Does the order of definitions matter, and why?
Learning objectives
- Import specific names from modules with from…import
- Import multiple names in one from…import statement
- Choose between import module and from module import
Key concepts
- from…import
- selective import
- namespace
Try it
Concept detail
“from module import name” brings a specific name into the current namespace.
from math import sqrt
sqrt(9) # call directly, no math. prefix needed
from math import sqrt, pi, ceil
# import multiple names in one line
from random import choice, shuffle, randintWHY use from…import:
- Reduces visual noise when a function is called frequently
- “sqrt(variance)” is cleaner than “math.sqrt(variance)” inside a math-heavy function
- Common in scientific code (numpy, pandas, sklearn all use it)
WHY to avoid “from module import *”:
- Dumps every name in the module into your namespace
- “where did ‘choice’ come from?” — impossible to answer by reading the code
- Risk of silently overwriting a name you already defined
Alias with “as”: from math import sqrt as square_root from datetime import datetime as dt
Decision guide:
- “import math” → when you need a few functions, clarity matters, or avoiding collisions
- “from math import X” → when X is used many times and the prefix hurts readability
- “from module import *” → almost never
Solution
from math import sqrt, log
from random import choice
def std_dev(numbers):
n = len(numbers)
mean = sum(numbers) / n
variance = sum((x - mean) ** 2 for x in numbers) / n
return sqrt(variance)
def log_scale(value, base=10):
return log(value, base)
def sample_item(items):
return choice(items)Tests
def test_std_dev_uniform():
# Classic dataset: mean=5, variance=4, stdev=2
assert std_dev([2, 4, 4, 4, 5, 5, 7, 9]) == 2.0
def test_std_dev_equal():
assert std_dev([5, 5, 5, 5]) == 0.0
def test_std_dev_two():
import math
assert abs(std_dev([0, 10]) - 5.0) < 0.0001
def test_log_scale_base10():
assert abs(log_scale(100) - 2.0) < 0.0001
def test_log_scale_base2():
assert abs(log_scale(8, 2) - 3.0) < 0.0001
def test_sample_item():
items = [1, 2, 3, 4, 5]
result = sample_item(items)
assert result in items