Module 4 · Functions & Modularity ⏱ 14 min

Modules & the Standard Library

By the end of this lesson you will be able to:
  • Import code from a module with import and from
  • Use standard-library tools like math, random, and collections
  • Count items quickly with collections.Counter
  • Explain why the dot keeps names namespaced and why star imports are risky

A module is a file of reusable Python code, and Python ships with an enormous standard library of them — no install required. You pull one in with import, then use its tools through the module's name:

import math
print(math.sqrt(25))     # 5.0
print(round(math.pi, 2))  # 3.14

The dot in math.sqrt is not decoration. It means 'the sqrt that lives inside math,' which keeps things namespaced: you always know where a tool came from, and two modules can offer functions with the same name without colliding. Anything the standard library does, you could write yourself — but you would be reinventing wheels that are already tested, fast, and documented.

flowchart LR
  P["your_program.py"] -->|import| M1["math"]
  P -->|import| M2["random"]
  P -->|import| M3["collections"]
  style P fill:#3776ab,color:#fff
Your program imports ready-made tools from the standard library instead of rewriting them.

Three modules you will use constantly

  • mathsqrt, pi, ceil, floor, and log.
  • randomrandom.randint(1, 6) for a dice roll, random.choice(['heads', 'tails']) to pick one item.
  • collections — and especially Counter, which tallies how many times each item appears.
from collections import Counter
counts = Counter('mississippi')
print(counts['s'])   # 4
print(counts['p'])   # 2

In tests, seed random with random.seed(0) so the results are deterministic and repeatable; in a quick interactive demo it does not matter.

Square root, a rounded constant, and a Counter tally. Press Run.
import math
from collections import Counter

print(math.sqrt(25))
print(round(math.pi, 2))

counts = Counter('mississippi')
print(counts['s'])
print(counts['p'])

Import styles and namespaces

Python offers two main ways to bring a name in. import math keeps the prefix — you write math.sqrt, which is a little verbose but completely unambiguous. from math import sqrt pulls a single name in directly, so you write just sqrt. Reach for the second form when you use one tool many times and the shorter name genuinely reads better.

Avoid from math import *, the star import. It dumps every name from the module into yours silently, and if two modules define a name like log, the last import wins without any warning. Explicit imports keep collisions impossible and make it obvious to the next reader where each tool came from.

flowchart LR
  M["import math"] --> U1["math.sqrt(25)"]
  F["from math import sqrt"] --> U2["sqrt(25)"]
  S["from math import *"] --> W["all names dumped in - risky"]
  style U1 fill:#3776ab,color:#fff
  style U2 fill:#3776ab,color:#fff
  style W fill:#b45309,color:#fff
import keeps the prefix; from-import drops it; star imports dump everything and risk collisions.

What import actually does

When Python hits import math, it runs the module's code once and stores the result in a module object — so the second import is essentially free, because the module is already cached. The same mechanism lets you split your own project across files: a file named stats.py becomes the module stats, and another file can import stats to reuse everything inside it.

A handy detail: every module carries a __name__. When you run a file directly, its __name__ is '__main__'; when it is imported, __name__ is the module's actual name. That is why you so often see if __name__ == '__main__': guarding demo code — it keeps the examples from running merely because someone imported the module.

Two ways to reach the same tool, plus the statistics module.
import math
from math import ceil
import statistics

# math.floor keeps the prefix; ceil was imported by name
print(math.floor(3.9), ceil(3.1))

# statistics is another standard-library gem
print(statistics.mean([4, 8, 15, 16, 23, 42]))
Exercise

Using math.pi, write circle_area(r) that returns the area of a circle with radius r (pi times r squared).

import math

def circle_area(r):
    # use math.pi
    pass
Exercise

Using Counter, write top_letter(text) that returns the single most common letter in text (as a string). Return None if text is empty.

from collections import Counter

def top_letter(text):
    # Counter(text).most_common(1) returns a list like [('l', 2)]
    pass
Exercise

What does this print? Two lines: a square root and a ceiling.

import math
print(math.sqrt(144))
print(math.ceil(3.2))
Exercise

This imports math but then calls sqrt without its prefix, so sqrt is not in scope. Fix it so hypotenuse(3, 4) returns 5.0.

import math

def hypotenuse(a, b):
    return sqrt(a * a + b * b)   # bug: sqrt is not in scope
Exercise

Write letter_frequency(text) that returns a Counter of how often each letter appears, ignoring case and skipping anything that is not a letter. So letter_frequency('Hello') returns {'h': 1, 'e': 1, 'l': 2, 'o': 1}.

from collections import Counter

def letter_frequency(text):
    # build a Counter over the lowercased letters only
    pass

Discovering what a module offers

You rarely memorize a whole module. Instead you ask Python what is inside. Pass a module to dir() and it lists every name it defines — functions, constants, and the dunder names you can usually ignore. Want a fuller explanation? help(sorted) prints a compact reference for any function or module, pulled straight from its docstring:

import math
print('sqrt' in dir(math))   # True
help(math.sqrt)

When a function's purpose is not obvious from its name, help is faster than a web search and always matches your installed version. Reading the official docs alongside dir and help is how working programmers learn a new module in minutes rather than days.

Aliases: renaming an import

Sometimes a module or name has a long, awkward name, or one that collides with your own. Python lets you rename an import as you bring it in with as:

import math as m
from math import sqrt as square_root

print(m.pi)
print(square_root(16))

The alias is purely a local label — it changes nothing about the module itself. This pattern shines with third-party libraries that the community has settled on short names for, such as import numpy as np. Inside a single file, pick the clearest name and use it consistently; renaming the same module three different ways in one program is a fast way to confuse your readers.

Beyond the standard library

The standard library is large, but it cannot cover everything. For tasks like web requests, image handling, or data tables, Python draws on third-party packages that other people have published. You install one from the command line with the pip tool, and then import it exactly as you would a built-in module.

A few habits keep this painless. Prefer the standard library when it already does the job, because it has no install step and ships with Python. When you do reach for a package, pin a known version so your program does not break when the package changes. And read a package's documentation before trusting it with real data — popularity is a hint, not a guarantee of quality.

Recap

  • A module is reusable code; import pulls it in, and the dot keeps its tools namespaced.
  • import math keeps the prefix; from math import sqrt drops it; avoid from math import *.
  • math, random, and collections cover a huge range of everyday tasks — Counter tallies, random rolls, math computes.
  • Each module runs once on first import and is cached; guard demo code with if __name__ == '__main__':.

Next you will turn a folder of your own modules into a package others can import and reuse.

Checkpoint quiz

Which line imports only the sqrt function from the math module?

What does Counter('aabbb')['b'] return?

Why is from math import * discouraged?

Go deeper — technical resources