← Home

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 did log come from? Use explicit names.

Rule: Use from X import Y when Y is used heavily and the prefix clutters. Use import math when 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, randint

WHY 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

Resources