Python Basics — Modules & Packages Practice Exercises

4 minute read

Modules & Packages — Practice Exercises

Test your understanding of imports, the standard library, creating modules, packages, and virtual environments.


Exercise 1 — Standard Library Explorer

Without running the code, predict the output. Then verify.

import math
import os
from datetime import date, timedelta

print(math.ceil(4.01))
print(math.floor(-3.7))
print(os.path.join("home", "user", "docs"))
print((date(2025, 3, 10) - date(2025, 3, 3)).days)
print(date(2025, 1, 1) + timedelta(days=59))
Show Solution
import math
import os
from datetime import date, timedelta

print(math.ceil(4.01))      # 5
print(math.floor(-3.7))     # -4
print(os.path.join("home", "user", "docs"))  # home/user/docs (or home\user\docs on Windows)
print((date(2025, 3, 10) - date(2025, 3, 3)).days)  # 7
print(date(2025, 1, 1) + timedelta(days=59))  # 2025-03-01 (Jan: 31 + Feb: 28 = 59 → Mar 1)

Exercise 2 — Create a Utility Module

Create a module called text_tools.py with these functions:

  1. word_count(text) — returns the number of words
  2. char_frequency(text) — returns a dict of character frequencies (ignoring spaces)
  3. reverse_words(text) — reverses the order of words
# Expected usage:
from text_tools import word_count, char_frequency, reverse_words

print(word_count("hello world foo"))         # 3
print(char_frequency("hello"))               # {'h': 1, 'e': 1, 'l': 2, 'o': 1}
print(reverse_words("hello world python"))   # "python world hello"
Show Solution
# text_tools.py
"""Text utility functions."""

__all__ = ["word_count", "char_frequency", "reverse_words"]

def word_count(text):
    """Return the number of words in the text."""
    return len(text.split())

def char_frequency(text):
    """Return a dictionary of character frequencies, ignoring spaces."""
    freq = {}
    for char in text:
        if char != " ":
            freq[char] = freq.get(char, 0) + 1
    return freq

def reverse_words(text):
    """Return the text with words in reverse order."""
    return " ".join(text.split()[::-1])

if __name__ == "__main__":
    print(word_count("hello world foo"))         # 3
    print(char_frequency("hello"))               # {'h': 1, 'e': 1, 'l': 2, 'o': 1}
    print(reverse_words("hello world python"))   # python world hello

Exercise 3 — Package Structure

Design a package structure for a simple e-commerce application. The package should have:

  • A models/ sub-package with product.py and user.py
  • A utils/ sub-package with validators.py
  • The main package __init__.py should export Product, User, and validate_email

Write the directory structure and all __init__.py files.

Show Solution
ecommerce/
├── __init__.py
├── models/
│   ├── __init__.py
│   ├── product.py
│   └── user.py
└── utils/
    ├── __init__.py
    └── validators.py
# ecommerce/models/product.py
class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price

    def __repr__(self):
        return f"Product({self.name}, ₹{self.price})"

# ecommerce/models/user.py
class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

    def __repr__(self):
        return f"User({self.name}, {self.email})"

# ecommerce/utils/validators.py
import re

def validate_email(email):
    pattern = r'^[\w\.-]+@[\w\.-]+\.\w+$'
    return bool(re.match(pattern, email))

# ecommerce/models/__init__.py
from .product import Product
from .user import User

# ecommerce/utils/__init__.py
from .validators import validate_email

# ecommerce/__init__.py
"""E-commerce package."""
from .models import Product, User
from .utils import validate_email

__all__ = ["Product", "User", "validate_email"]
# Usage:
from ecommerce import Product, User, validate_email

laptop = Product("Laptop", 75000)
alice = User("Alice", "alice@example.com")
print(laptop)                           # Product(Laptop, ₹75000)
print(alice)                            # User(Alice, alice@example.com)
print(validate_email("alice@example.com"))  # True

Exercise 4 — Virtual Environment Workflow

Write the complete sequence of terminal commands to:

  1. Create a new project directory my-api
  2. Create and activate a virtual environment
  3. Install flask and requests
  4. Save dependencies to requirements.txt
  5. Show contents of requirements.txt
Show Solution
# 1. Create project directory
mkdir my-api
cd my-api

# 2. Create and activate virtual environment
python -m venv venv
source venv/bin/activate  # macOS/Linux
# venv\Scripts\activate   # Windows

# 3. Install packages
pip install flask requests

# 4. Save dependencies
pip freeze > requirements.txt

# 5. View dependencies
cat requirements.txt
# Output (versions may vary):
# blinker==1.7.0
# certifi==2023.11.17
# charset-normalizer==3.3.2
# click==8.1.7
# flask==3.0.0
# idna==3.6
# itsdangerous==2.1.2
# Jinja2==3.1.2
# MarkupSafe==2.1.3
# requests==2.31.0
# urllib3==2.1.0
# Werkzeug==3.0.1

To recreate on another machine:

python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Exercise 5 — import Detective

What’s wrong with each of these? Fix them.

# Problem 1
from math import *
result = sqrt(16) + ceil(4.2) + floor(3.8)

# Problem 2
# File: random.py
import random
print(random.randint(1, 10))

# Problem 3
import my_module
# ...later
import my_module  # Is this a performance issue?

# Problem 4
def calculate():
    import math
    return math.sqrt(16)
# Called 10,000 times in a loop
Show Solution
# Problem 1 — import * pollutes namespace
# Fix: import specific names
from math import sqrt, ceil, floor
result = sqrt(16) + ceil(4.2) + floor(3.8)
print(result)  # 4.0 + 5 + 3 = 12.0

# Problem 2 — file name shadows the built-in module
# Fix: rename your file to something else (e.g., my_random.py)
# NEVER name your file: math.py, random.py, os.py, json.py, etc.

# Problem 3 — NOT a performance issue
# Python caches module imports in sys.modules
# The second `import my_module` just references the cached version
# No re-execution occurs
import sys
# print('my_module' in sys.modules)  # True after first import

# Problem 4 — import inside function is OK but not ideal
# Python caches it after the first call, so performance is fine
# But PEP 8 recommends imports at the top of the file
# Fix: move import to top
import math

def calculate():
    return math.sqrt(16)

Scoring Guide

Score Level
5/5 ⭐ Module master — ready to build real projects
3-4/5 👍 Good understanding — practice creating packages
1-2/5 📚 Revisit import styles, init.py, and virtual environments

Next chapter: File Handling →

Updated: