Modules
A module is simply a file containing Python code. Any file that ends in .py is a module, and its name is the filename without the .py extension. Modules let you organize related code — functions, classes, variables — into reusable files instead of cramming everything into one giant script.
Once code lives in a module, you can import it from another file. This is the foundation of how Python programs scale: instead of one huge file, you split logic across many small, focused modules and wire them together with imports.
Why use modules?
Reusability — write a function once, use it in many scripts.
Organization — group related functionality together (e.g. all math helpers in one file).
Namespacing — avoid naming collisions by keeping code inside its own module namespace.
Maintainability — smaller files are easier to read, test, and debug.
Ways to import
Python gives you a few different syntaxes for importing, depending on how much of the module's namespace you want to bring in.
# 1. import the whole module — access members with a prefix import math print(math.sqrt(16)) # 4.0 print(math.pi) # 3.141592653589793 # 2. import specific names directly into your namespace from math import sqrt, pi print(sqrt(16)) # 4.0 print(pi) # 3.141592653589793 # 3. import with an alias — common for long or conflicting names import math as m print(m.sqrt(25)) # 5.0 # 4. import everything (generally discouraged — pollutes your namespace) from math import * print(floor(3.7)) # 3
from module import * in real projects — it makes it unclear where a name came from and can silently overwrite names you already have.A quick hypothetical example
Imagine a file named shapes.py that defines a couple of helper functions:
# shapes.py
def area_circle(radius):
return 3.14159 * radius ** 2
def area_square(side):
return side ** 2Any other file in the same directory can now use it:
# main.py import shapes print(shapes.area_circle(2)) # 12.56636 print(shapes.area_square(3)) # 9
The if __name__ == "__main__": guard
Every module has a built-in variable called __name__. When a file is run directly (e.g. python greetings.py), Python sets __name__ to the string "__main__". When that same file is imported by another module, __name__ is set to the module's own name instead.
This lets a single file work both as a standalone script and as an importable module — the guard only runs the "script" behavior when the file is executed directly, not when it's imported.
File: greetings.py
# greetings.py
def greet(name):
return f"Hello, {name}!"
def main():
# This is the "script" behavior — only for direct execution
name = input("What is your name? ")
print(greet(name))
if __name__ == "__main__":
main()File: app.py
# app.py
import greetings
# We only want the greet() function here — main() never runs,
# because __name__ is "greetings", not "__main__", during this import.
message = greetings.greet("Ada")
print(message)Hello, Ada!
Creating and importing your own module
Let's build a small calculator module with a few functions, then use it from a separate entry-point file.
File: calculator.py
# calculator.py
def add(a, b):
return a + b
def subtract(a, b):
return a - b
def multiply(a, b):
return a * b
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / bFile: main.py
# main.py from calculator import add, subtract, multiply, divide print(add(4, 5)) # 9 print(subtract(10, 3)) # 7 print(multiply(6, 7)) # 42 print(divide(20, 4)) # 5.0
9 7 42 5.0
As long as calculator.py and main.py live in the same directory, from calculator import ... works with no extra setup — Python finds calculator.py on its module search path automatically (more on this in The Import System).
Inspecting a module with dir()
The built-in dir() function lists all the names — functions, classes, variables — defined inside a module. This is a handy way to explore what a module offers without reading its source.
import math print(dir(math))
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'isqrt', 'lcm', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi', 'pow', 'prod', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
Names surrounded by double underscores (like __name__ and __doc__) are special "dunder" attributes that Python itself uses. The rest — sqrt, pi, floor, and so on — are the module's public API.
math.py or random.py in your project directory will shadow the standard library module of the same name, causing confusing import errors elsewhere in your code.