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
Three modules you will use constantly
math—sqrt,pi,ceil,floor, andlog.random—random.randint(1, 6)for a dice roll,random.choice(['heads', 'tails'])to pick one item.collections— and especiallyCounter, 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.
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
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.
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]))
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
Import math, then use math.pi.
Area is math.pi times r times r.
import math
def circle_area(r):
return math.pi * r * r
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
Guard the empty case first: if not text: return None.
most_common(1)[0][0] is the letter of the top pair.
from collections import Counter
def top_letter(text):
if not text:
return None
return Counter(text).most_common(1)[0][0]
What does this print? Two lines: a square root and a ceiling.
import math print(math.sqrt(144)) print(math.ceil(3.2))
The square root of 144 is 12.0 (sqrt always returns a float).
ceil rounds up, so 3.2 becomes 4.
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
import mathkeeps the prefix, so you must write math.sqrt.Alternatively you could
from math import sqrt, but the prefix form is clearer here.
import math
def hypotenuse(a, b):
return math.sqrt(a * a + b * b)
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
Feed Counter a generator that yields c.lower() for letters only.
Skip non-letters with
if c.isalpha().
from collections import Counter
def letter_frequency(text):
return Counter(c.lower() for c in text if c.isalpha())
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;
importpulls it in, and the dot keeps its tools namespaced. import mathkeeps the prefix;from math import sqrtdrops it; avoidfrom math import *.math,random, andcollectionscover a huge range of everyday tasks —Countertallies,randomrolls,mathcomputes.- 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.