Modules & Imports

Python · Lesson 28 of 56 7 min read Updated

As your programs grow, one long file becomes hard to manage. Python lets you split code into modules: separate .py files that you load with the import statement. Python itself ships with hundreds of ready-made modules, called the standard library, for maths, dates, files, JSON and much more.

In this lesson you will learn the different ways to import, how to write your own module, what if __name__ == "__main__": means, and how to group modules into packages.

Importing a module

A module is simply a Python file. When you write import math, Python finds the math module, runs it once and gives you a name, math, through which you reach everything inside it with a dot.

PythonRun it yourself
import math
import statistics

print(math.sqrt(144))
print(math.ceil(7.2))
print(math.pi)

marks = [72, 85, 91, 64, 85]
print(statistics.mean(marks))
print(statistics.mode(marks))
Output
12.0
8
3.141592653589793
79.4
85

The dot shows clearly where each name comes from: math.sqrt is the square root function from the math module. Put your imports at the top of the file, one module per line.

Other ways to import

There are four common import forms. Each one suits a different situation.

PythonRun it yourself
import statistics as stats             # 1. a shorter alias
from math import floor, factorial      # 2. pick specific names
from datetime import date as Date      # 3. pick a name and rename it

print(stats.median([4, 9, 2, 7, 5]))
print(floor(9.99), factorial(5))
print(Date(2026, 1, 26).year)
Output
5
9 120
2026
FormYou writeUse it when
import mathmath.sqrt(9)Most of the time; the source is always clear
import statistics as statsstats.mean(x)The module name is long or has a common short form
from math import sqrtsqrt(9)You use a few names many times
from math import *sqrt(9)Avoid: it dumps every name into your file and can hide your own variables

Writing your own module

Any .py file you write is a module that other files can import. Imagine two files in the same folder. The first one, gst_utils.py, holds reusable functions:

Python
# gst_utils.py
GST_RATE = 18

def add_gst(price):
    return round(price * (100 + GST_RATE) / 100, 2)

def gst_amount(price):
    return round(price * GST_RATE / 100, 2)

The second file, main.py, imports and uses them:

Python
# main.py
import gst_utils

print(gst_utils.add_gst(1000))
print(gst_utils.gst_amount(1299))
print(gst_utils.GST_RATE)
Output
1180.0
233.82
18

Run it with python main.py from that folder. Python looks for modules first in the folder of the script you run, then in the standard library and finally in installed packages. The browser editor has only one file, so this runnable version writes gst_utils.py first and then imports it:

PythonRun it yourself
from pathlib import Path

Path("gst_utils.py").write_text(
    "GST_RATE = 18\n"
    "def add_gst(price):\n"
    "    return round(price * (100 + GST_RATE) / 100, 2)\n",
    encoding="utf-8",
)

from gst_utils import add_gst, GST_RATE
print(add_gst(1000), GST_RATE)
Output
1180.0 18

The __name__ variable and if __name__ == "__main__":

Every module has a built-in variable called __name__. When you run a file directly, Python sets its __name__ to the string "__main__". When the file is imported, __name__ is the module's own name, such as "gst_utils".

This lets one file work both as a program and as a module. Code inside the if block below runs when you start the file directly, but not when another file imports it:

PythonRun it yourself
def add_gst(price):
    return round(price * 1.18, 2)

def main():
    print("Quick GST check:")
    for price in [100, 499, 1299]:
        print(price, "->", add_gst(price))

print("__name__ is", __name__)

if __name__ == "__main__":
    main()
Output
__name__ is __main__
Quick GST check:
100 -> 118.0
499 -> 588.82
1299 -> 1532.82

Without this check, importing the file would also run its demo code and print output you did not ask for. Putting the program's start-up code in a main() function and calling it from this block is a common and tidy habit.

Packages: folders of modules

A package is a folder that groups related modules. A regular package contains a file called __init__.py, which runs when the package is first imported and is often empty. You import modules from it with dots.

Text
shop/
    __init__.py
    billing.py
    stock.py
main.py
Python
# main.py
from shop.billing import make_bill
from shop import stock

make_bill(["pen", "notebook"])
stock.check("pen")

Packages you install with pip, such as requests, are organised the same way. You will install packages in pip & Virtual Environments.

Common mistakes

  • Naming your file after a module. If you save your script as random.py or json.py, then import random loads your file instead of the standard one, and you get strange errors such as AttributeError: module 'random' has no attribute 'randint'. Recent Python versions add a hint to that message suggesting you rename your file. Do it.
  • Using from module import *. You cannot tell where names come from, and imported names can silently replace your own.
  • Running a module from the wrong folder. ModuleNotFoundError: No module named 'gst_utils' usually means you are not in the folder that contains the file.
  • Expecting a second import to rerun the file. Python runs a module only once per program and reuses it for later imports.

Key points

  • A module is a .py file; import name loads it once and you reach its contents with name.something.
  • import x as y creates an alias, and from x import a, b brings in chosen names; avoid import *.
  • Your own files are modules too; Python searches the script's folder first.
  • __name__ is "__main__" only when a file is run directly, so if __name__ == "__main__": holds start-up code.
  • A package is a folder of modules, usually with an __init__.py file, imported with dotted names.
  • Python 3.15 adds lazy import at module level to delay loading until first use.

Exercise

Create a module called cricket_stats.py with two functions: strike_rate(runs, balls), which returns runs per 100 balls rounded to 2 decimal places, and average(runs, outs), which returns runs per dismissal rounded to 2 places. Add an if __name__ == "__main__": block that prints a quick test. Then write main.py that imports the module and prints the strike rate for 87 runs off 54 balls and the average for 1,432 runs with 31 outs.

Show solution
Python
# cricket_stats.py
def strike_rate(runs, balls):
    return round(runs / balls * 100, 2)

def average(runs, outs):
    return round(runs / outs, 2)

if __name__ == "__main__":
    print("Test:", strike_rate(50, 25), average(300, 6))
Python
# main.py
import cricket_stats

print(cricket_stats.strike_rate(87, 54))
print(cricket_stats.average(1432, 31))
Output
161.11
46.19

Running python main.py prints only the two results. The test line in cricket_stats.py runs only when you start that file directly, because then its __name__ is "__main__".

Quick Quiz

1. What is a Python module?

2. When does the code under if __name__ == "__main__": run?

3. You saved your script as random.py, and import random now fails strangely. Why?

4. Where can you use lazy import json in Python 3.15?

Learn Python with a mentor

Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call