Skip to content
C

Modules & Packages

Organizing code into modules and packages, the different ways to import, __name__ == "__main__", and a practical tour of the Standard Library (math, random, datetime, os, sys, json, re, statistics, collections, itertools, functools).


As programs grow, it doesn't make sense to keep everything in one giant file — and you also don't want to rewrite common functionality (like math operations or date handling) from scratch every time. Python solves this with modules and packages, plus a massive built-in Standard Library of ready-to-use tools.


1. What is a Module?

What is it?

A module is simply a Python file (.py) containing code — variables, functions, classes — that can be reused in other Python files by importing it.

Definition: A module is a single Python file containing reusable code that can be imported into other programs.

Why do we use it?

  • Organization — split a large program into logical, manageable files.
  • Reusability — write a function once, use it in many different programs.
  • Avoid repetition — no need to rewrite common logic (like date calculations) every time.

How does it work?

Any .py file is automatically a module. You bring its contents into another file using the import keyword.

Simple Example — Creating Your Own Module

File: `mymath.py`

python
def add(a, b): return a + b def subtract(a, b): return a - b

File: `main.py` (in the same folder)

python
import mymath print(mymath.add(5, 3)) # 8 print(mymath.subtract(5, 3)) # 2

Explanation of the Code

  • import mymath loads everything defined inside mymath.py, making it available through mymath.functionname().
  • The module name is just the filename, without the .py extension.

Common Mistakes

  • Trying to import a module that isn't in the same folder (or on Python's search path), causing ModuleNotFoundError.
  • Naming your own file the same as a well-known library (e.g., naming your file random.py), which can conflict with Python's built-in modules.

Important Points

  • Any .py file can be treated as a module.
  • The module name matches the filename (without .py).

2. Different Ways to Import

Syntax Options

python
import math # import the whole module print(math.sqrt(16)) # access with module_name.function() from math import sqrt # import just one function print(sqrt(16)) # use it directly, no prefix needed from math import sqrt, pow # import multiple specific items import math as m # import with an alias (shorter name) print(m.sqrt(16)) from math import * # import EVERYTHING (generally discouraged)

Explanation

  • import math keeps things organized — you always know a function like sqrt() came from math because you write math.sqrt().
  • from math import sqrt is more convenient when you use a function frequently, but it's less clear where the function came from, especially in larger files.
  • import math as m is common for long library names (very frequently seen with libraries like pandas as pd or numpy as np).

Common Mistakes

  • Using from module import *, which can cause naming conflicts if two modules define something with the same name — it's discouraged in real projects for this reason.
  • Forgetting to install a third-party module before importing it (built-in modules like math need no installation, but others like requests do — covered in the Package Management file).

Important Points

  • import module_name is the safest, clearest default choice.
  • Aliasing (as) is a widely used convention for popular libraries.

3. Packages

What is it?

A package is a folder containing multiple related modules, organized together — essentially, a "module of modules."

Definition: A package is a directory containing multiple Python modules, along with a special __init__.py file that marks it as a package.

Folder Structure Example

myapp/
    __init__.py
    calculations.py
    formatting.py

Simple Example

File: `myapp/calculations.py`

python
def add(a, b): return a + b

File: `main.py` (outside the myapp folder)

python
from myapp import calculations print(calculations.add(5, 3)) # 8

What is __init__.py?

This special (often empty) file tells Python "this folder is a package, not just a regular folder." Without it, older versions of Python won't recognize the folder as importable (modern Python 3 can sometimes work without it via "namespace packages," but including it is still standard, clear practice).

Real-World Example

Popular libraries like numpy or django are packages — large folders full of organized modules, all accessible through a single import numpy statement.

Common Mistakes

  • Forgetting __init__.py in a package folder, leading to unexpected import behavior in some setups.
  • Confusing "module" (single file) with "package" (folder of modules) — a common interview distinction.

Important Points

  • A package is a folder; a module is a single file.
  • __init__.py marks a folder as a package.

4. __name__ and __main__

What is it?

Every Python file has a built-in variable called __name__. When a file is run directly, __name__ is automatically set to "__main__". When the same file is imported into another file, __name__ is set to the module's actual name instead.

Why do we use it?

This lets you write code in a file that behaves differently depending on whether it's being run directly or just imported for its functions — extremely useful for testing a module's code without that test code running every time someone else imports it.

Simple Example

File: `greetings.py`

python
def greet(name): print(f"Hello, {name}!") if __name__ == "__main__": greet("Test User") # only runs when this file is executed directly
  • Running python greetings.py directly → prints "Hello, Test User!".
  • Running import greetings from another file → the greet() function is available, but "Hello, Test User!" does not print automatically.

Real-World Example

Almost every well-structured Python script or library uses this pattern so that importing it for its functions doesn't accidentally trigger test code or a demo run meant only for direct execution.

Common Mistakes

  • Forgetting this check entirely, causing test/demo code to run unexpectedly whenever the file is imported elsewhere.

Important Points

  • __name__ == "__main__" is a near-universal pattern in real Python projects.
  • It distinguishes "this file was run directly" from "this file was imported."

Practice

  1. Create a module with a function and a if __name__ == "__main__": block that tests the function. Run it directly, then import it from another file and observe the difference.

5. The Python Standard Library — A Practical Tour

Python comes bundled with a huge collection of built-in modules — no installation required. Here are the most commonly used ones.

5.1 math — Mathematical Functions

python
import math print(math.sqrt(25)) # 5.0 print(math.pow(2, 3)) # 8.0 print(math.floor(4.7)) # 4 print(math.ceil(4.2)) # 5 print(math.pi) # 3.141592653589793

Real-World Use: Calculating distances, geometry, engineering formulas.

5.2 random — Random Number Generation

python
import random print(random.randint(1, 100)) # random integer between 1 and 100 print(random.choice(["A", "B", "C"])) # random item from a list print(random.random()) # random float between 0.0 and 1.0 items = [1, 2, 3, 4, 5] random.shuffle(items) # shuffles the list in place print(items)

Real-World Use: Games (like the Number Guessing Game), generating OTPs, shuffling quiz questions.

5.3 datetime — Dates and Times

python
from datetime import datetime, date now = datetime.now() print(now) # e.g. 2026-09-02 14:30:00.123456 print(now.year, now.month, now.day) birth_date = date(2000, 5, 15) today = date.today() age_days = (today - birth_date).days print(f"You are {age_days} days old")

Real-World Use: Timestamps, age calculators, scheduling systems, log files.

5.4 os — Operating System Interaction

python
import os print(os.getcwd()) # current working directory os.mkdir("new_folder") # create a folder print(os.listdir(".")) # list files in current directory print(os.path.exists("main.py")) # check if a file exists

Real-World Use: File automation, checking/creating folders, working with file paths across operating systems.

5.5 sys — System-Specific Parameters

python
import sys print(sys.version) # Python version info print(sys.argv) # command-line arguments passed to the script

Real-World Use: Reading command-line arguments, exiting a script early with sys.exit().

5.6 json — Working with JSON Data

python
import json data = {"name": "Aditi", "age": 21} json_string = json.dumps(data) # Python dict -> JSON string print(json_string) # {"name": "Aditi", "age": 21} parsed = json.loads(json_string) # JSON string -> Python dict print(parsed["name"]) # Aditi

Real-World Use: APIs almost always send and receive data in JSON format — this module is essential for web development and API work (covered in depth later).

5.7 re — Regular Expressions

python
import re text = "Call me at 9876543210" match = re.search(r"\d{10}", text) if match: print("Phone number found:", match.group())

Real-World Use: Validating emails, phone numbers, passwords (covered in full in the Regular Expressions file).

5.8 statistics — Statistical Calculations

python
import statistics marks = [85, 90, 78, 92, 88] print(statistics.mean(marks)) # average print(statistics.median(marks)) # middle value print(statistics.mode(marks)) # most common value

Real-World Use: Quick statistical summaries without needing a heavier library like NumPy for simple cases.

5.9 collections — Specialized Data Structures

python
from collections import Counter, defaultdict words = ["apple", "banana", "apple", "cherry", "banana", "apple"] print(Counter(words)) # Counter({'apple': 3, 'banana': 2, 'cherry': 1}) word_count = defaultdict(int) for word in words: word_count[word] += 1 print(dict(word_count))

Explanation: Counter instantly counts occurrences of each item. defaultdict avoids KeyError by providing a default value (here, 0) for keys that don't exist yet.

Real-World Use: Word frequency counters, grouping and tallying data.

5.10 itertools — Efficient Looping Tools

python
import itertools # All possible pairs from a list for pair in itertools.combinations([1, 2, 3], 2): print(pair) # (1, 2) # (1, 3) # (2, 3)

Real-World Use: Generating combinations/permutations, efficient looping over large or infinite sequences.

5.11 functools — Functional Programming Tools

python
from functools import reduce, lru_cache total = reduce(lambda a, b: a + b, [1, 2, 3, 4]) print(total) # 10 @lru_cache(maxsize=None) def slow_square(n): return n * n print(slow_square(5)) # cached after first call

Explanation: @lru_cache automatically remembers previous results of a function, so repeated calls with the same input skip re-computation — useful for speeding up expensive functions like recursive calculations.

Real-World Use: Speeding up repeated expensive calculations (like recursive Fibonacci), combining values with reduce.

Comparison Table — Common Standard Library Modules

ModulePurpose
mathMathematical calculations
randomRandom values, shuffling, choices
datetimeDates and times
osFile system and OS interaction
sysSystem/interpreter-level info
jsonEncoding/decoding JSON data
rePattern matching in text
statisticsQuick statistical calculations
collectionsSpecialized containers (Counter, defaultdict)
itertoolsEfficient iteration tools
functoolsFunctional programming helpers (reduce, caching)

Common Beginner Mistakes — Summary

  • Using from module import *, risking naming conflicts.
  • Naming your own files the same as standard modules (e.g., random.py), which shadows the real module.
  • Forgetting __init__.py when building a package.
  • Forgetting that import only needs to happen once per file, at the top.
  • Confusing "module" (a file) with "package" (a folder of modules).

Cheat Sheet — Modules & Packages

python
import math # standard import from math import sqrt # import specific item import math as m # import with alias from math import * # import everything (avoid in real projects) if __name__ == "__main__": # code that runs only when this file is executed directly pass
myapp/                # package (folder)
    __init__.py        # marks it as a package
    module_one.py       # a module inside the package
    module_two.py

Interview Questions

Q1. What is the difference between a module and a package? Answer: A module is a single Python file. A package is a folder containing multiple related modules, along with an __init__.py file marking it as a package.

Q2. What does `if __name__ == "__main__":` do? Answer: It checks whether the current file is being run directly (in which case __name__ equals "__main__") rather than imported into another file — code inside this block only runs on direct execution.

*Q3. What is the risk of using `from module import `?** Answer: It can cause naming conflicts if multiple modules define something with the same name, and it makes it unclear where a given function or variable actually came from.

Q4. Name three commonly used Python Standard Library modules and their purpose. Answer: Examples: math (mathematical functions), datetime (dates and times), os (file system and operating system interaction), json (working with JSON data), random (random values).

Q5. What does `__init__.py` do in a package? Answer: It marks a folder as a Python package so its modules can be imported properly.


Practice Questions

Beginner

  1. Create your own module with two functions and import it into a separate file.
  2. Use the math module to calculate the square root and factorial of a number.
  3. Use the random module to simulate rolling a die (random number from 1 to 6).
  4. Use the datetime module to print today's date.
  5. Use the os module to list all files in the current directory.

Intermediate

  1. Create a package with two modules (operations.py and formatting.py) and use both in a main.py file.
  2. Use the json module to convert a dictionary of student data into a JSON string and back.
  3. Use collections.Counter to find the most common word in a list of words.
  4. Write a function that uses if __name__ == "__main__": to test itself only when run directly.
  5. Use the statistics module to calculate the mean, median, and mode of a list of exam scores.

Challenge

  1. Use itertools.permutations to generate all possible orderings of a 3-letter word.
  2. Build a simple age calculator using the datetime module that takes a birth date and prints the person's exact age in years, months, and days.
  3. Use functools.lru_cache to speed up a recursive Fibonacci function, and compare its execution time to the uncached version.

Mock Test

  • Modules & Packages - Quick Test

    10 questions covering modules, packages, imports, __name__ == "__main__", and the Python Standard Library.

    10 questions · 10 min · Easy
    Start Mock Test

Coding Problems