073. Importing Modules
Reuse existing libraries instead of reinventing the wheel
073. Importing Modules
He wants to display RAM usage as a percentage bar and compute log-scaled sizes for the process chart.
His first instinct: hand-roll everything.
PI = 3.14159 # close, but 6 digits of precision — not good enoughA classmate imports math instead:
import math
# math.pi → 3.141592653589793 (full float64)
# math.log2(rss_mb) — log scale for wildly different process sizes
# math.ceil(percent) — round UP to nearest whole percent
def scale_rss(rss_mb):
return math.log2(rss_mb) if rss_mb > 0 else 0
def bar_width(percent, max_width=40):
return math.ceil(percent / 100 * max_width)The rule: before writing any math utility, check import math. math.sqrt, math.log, math.ceil, math.floor, math.gcd, math.pi — all free, all tested.
💡 Fun fact: Python’s module system caches every imported module in sys.modules after the first import. This means import math in 100 different files across your program costs only one actual load — subsequent imports are essentially free dictionary lookups. This design is why Python can have thousands of small modules without startup overhead.
⚠️ Watch out: A very common mistake is naming your own file the same as a standard library module — e.g., saving your code as math.py or random.py. Python searches the current directory first, so import math would import your file instead of the standard library, causing mysterious AttributeError: module 'math' has no attribute 'sqrt' errors.
🤔 Think about it: math.pi gives you 3.141592653589793 — 16 significant digits. Is that enough precision for all real-world calculations? What kind of computation would require even more precision, and how would Python handle it?
Learning objectives
- Import modules using the import statement
- Access module attributes with dot notation
- Use math module functions and constants
Key concepts
- import
- module
- standard library
- math module
Try it
Concept detail
“import math” loads the math module and makes all its names available as math.X.
import math
math.pi → 3.141592653589793 (full float64 precision)
math.sqrt(9) → 3.0
math.log2(1024) → 10.0
math.ceil(4.1) → 5
math.floor(4.9) → 4
math.gcd(12, 8) → 4WHY use the standard library instead of reimplementing:
- math.pi has more digits than you can type correctly (3.14159 is off by 8e-6)
- math.sqrt is implemented in C — faster than x**0.5
- math.ceil handles edge cases (negative floats, large integers)
- Code reads like intent: math.ceil says “ceiling function”, not “(int(x) + …)”
Python’s import system:
- “import math” executes the module once, then caches it in sys.modules
- Re-importing (import math a second time) is free — returns the cached object
- Module = a .py file or C extension containing functions, classes, variables
Before writing any utility function, check docs.python.org/3/library — Python’s standard library has 200+ modules and it is probably already there.
Solution
import math
def circle_area(radius):
return math.pi * radius ** 2
def circle_circumference(radius):
return 2 * math.pi * radius
def hypotenuse(a, b):
return math.sqrt(a**2 + b**2)
def log2_rss(rss_mb):
return math.log2(rss_mb)Tests
def test_circle_area_precision():
import math
# PI=3.14159 is off by ~8e-6; math.pi is accurate to full float precision
assert abs(circle_area(1) - math.pi) < 1e-10
def test_circle_area_5():
import math
assert abs(circle_area(5) - math.pi * 25) < 1e-10
def test_circle_circumference():
import math
assert abs(circle_circumference(1) - 2 * math.pi) < 1e-10
def test_hypotenuse_345():
assert abs(hypotenuse(3, 4) - 5.0) < 0.0001
def test_hypotenuse_512():
assert abs(hypotenuse(5, 12) - 13.0) < 0.0001
def test_log2_rss():
assert abs(log2_rss(1024) - 10.0) < 0.0001
assert abs(log2_rss(1) - 0.0) < 0.0001