📦 Working with Modules and Packages

Modules and packages help you organize Python code into reusable components. They let you split large programs into smaller files, share code between projects, and use code written by others.

# Importing built-in modules
import math
import random
from datetime import datetime, timedelta

# Using imported modules
radius = 5
area = math.pi * radius ** 2
random_number = random.randint(1, 100)
current_time = datetime.now()
tomorrow = current_time + timedelta(days=1)

print(f"Circle area: {area:.2f}")
print(f"Random number: {random_number}")
print(f"Tomorrow: {tomorrow.strftime('%Y-%m-%d')}")

🎯 Understanding Modules and Packages

Modules are single Python files, while packages are directories containing multiple modules.

Basic Import Examples

# Different ways to import
import os
import json as js
from pathlib import Path
from collections import Counter, defaultdict

# Using imported items
current_dir = os.getcwd()
data = js.dumps({"name": "Alice", "age": 30})
file_path = Path("example.txt")
word_count = Counter(['apple', 'banana', 'apple'])

print(f"Current directory: {current_dir}")
print(f"JSON data: {data}")
print(f"File exists: {file_path.exists()}")
print(f"Word counts: {word_count}")

Creating Your Own Module

# Example of what you'd put in a file called 'my_utils.py'
"""
# Content of my_utils.py
def greet(name, style="casual"):
    if style == "formal":
        return f"Good day, {name}."
    else:
        return f"Hey {name}!"

def calculate_tax(amount, rate=0.08):
    return amount * rate

def format_currency(amount, currency="USD"):
    return f"{amount:.2f} {currency}"

# Module-level variable
DEFAULT_TAX_RATE = 0.08
"""

# How to use your custom module
# import my_utils

# message = my_utils.greet("Alice", "formal")
# tax = my_utils.calculate_tax(100, my_utils.DEFAULT_TAX_RATE)
# formatted = my_utils.format_currency(108.0)

# For demonstration, we'll simulate the module
class MyUtils:
    DEFAULT_TAX_RATE = 0.08
    
    @staticmethod
    def greet(name, style="casual"):
        if style == "formal":
            return f"Good day, {name}."
        else:
            return f"Hey {name}!"
    
    @staticmethod
    def calculate_tax(amount, rate=0.08):
        return amount * rate
    
    @staticmethod
    def format_currency(amount, currency="USD"):
        return f"{amount:.2f} {currency}"

my_utils = MyUtils()
message = my_utils.greet("Alice", "formal")
tax = my_utils.calculate_tax(100, my_utils.DEFAULT_TAX_RATE)
formatted = my_utils.format_currency(108.0)

print(f"Message: {message}")
print(f"Tax: {tax}")
print(f"Formatted: {formatted}")

📋 Import Methods Reference

MethodSyntaxUse Case
Full importimport moduleAccess as module.item
Specific importfrom module import itemUse item directly
Multiple importsfrom module import a, b, cImport several items
Alias importimport module as aliasShorter or clearer names
All importsfrom module import *Import everything (avoid)

🔧 Common Built-in Modules

Working with Files and Paths

import os
from pathlib import Path

# Using os module
current_directory = os.getcwd()
files_in_dir = os.listdir('.')
home_directory = os.path.expanduser('~')

print(f"Current dir: {current_directory}")
print(f"Files: {files_in_dir[:3]}")  # Show first 3 files

# Using pathlib (modern approach)
current_path = Path.cwd()
home_path = Path.home()

# Create path objects
config_file = current_path / "config.txt"
data_dir = current_path / "data"

print(f"Config file path: {config_file}")
print(f"Data directory: {data_dir}")
print(f"Config exists: {config_file.exists()}")

Date and Time Operations

from datetime import datetime, date, timedelta
import time

# Current date and time
now = datetime.now()
today = date.today()

# Time calculations
next_week = now + timedelta(weeks=1)
yesterday = today - timedelta(days=1)

# Formatting dates
formatted_date = now.strftime("%Y-%m-%d %H:%M")
iso_date = now.isoformat()

print(f"Now: {formatted_date}")
print(f"Next week: {next_week.date()}")
print(f"Yesterday: {yesterday}")

# Working with timestamps
timestamp = time.time()
readable_time = time.ctime(timestamp)
print(f"Timestamp: {timestamp}")
print(f"Readable: {readable_time}")

JSON and Data Processing

import json
from collections import Counter, defaultdict

# Working with JSON
data = {
    "users": [
        {"name": "Alice", "age": 30, "city": "Boston"},
        {"name": "Bob", "age": 25, "city": "New York"},
        {"name": "Charlie", "age": 35, "city": "Boston"}
    ]
}

# Convert to JSON string
json_string = json.dumps(data, indent=2)
print("JSON string:")
print(json_string[:100] + "...")

# Parse JSON string back to Python
parsed_data = json.loads(json_string)
print(f"First user: {parsed_data['users'][0]['name']}")

# Using collections
ages = [user['age'] for user in data['users']]
cities = [user['city'] for user in data['users']]

age_counter = Counter(ages)
city_groups = defaultdict(list)

for user in data['users']:
    city_groups[user['city']].append(user['name'])

print(f"Age distribution: {dict(age_counter)}")
print(f"City groups: {dict(city_groups)}")

📊 Package Structure Example

my_project/
├── main.py
├── utils/
│   ├── __init__.py
│   ├── helpers.py
│   └── validators.py
├── data/
│   ├── __init__.py
│   └── processors.py
└── tests/
    ├── __init__.py
    └── test_utils.py

Creating Package Structure

# Example package structure (simulated)

# utils/__init__.py content:
"""
from .helpers import format_name, clean_text
from .validators import is_email_valid, is_phone_valid
"""

# utils/helpers.py content:
def format_name(first, last):
    return f"{first.title()} {last.title()}"

def clean_text(text):
    return text.strip().lower()

# utils/validators.py content:
import re

def is_email_valid(email):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email))

def is_phone_valid(phone):
    # Simple phone validation
    digits = re.sub(r'\D', '', phone)
    return len(digits) == 10

# Simulating package usage
# from utils import format_name, is_email_valid

# For demonstration purposes:
def format_name(first, last):
    return f"{first.title()} {last.title()}"

def is_email_valid(email):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email))

# Using the package functions
name = format_name("alice", "johnson")
valid_email = is_email_valid("alice@example.com")
invalid_email = is_email_valid("not-an-email")

print(f"Formatted name: {name}")
print(f"Valid email: {valid_email}")
print(f"Invalid email: {invalid_email}")

Module Search Path

import sys

# Python module search path
print("Python searches for modules in these locations:")
for i, path in enumerate(sys.path[:5], 1):
    print(f"{i}. {path}")

# Module information
import math
print(f"\nMath module location: {math.__file__}")
print(f"Math module name: {math.__name__}")

# Check if module is available
try:
    import requests
    print("Requests module is available")
except ImportError:
    print("Requests module is not installed")

Conditional Imports

# Conditional imports for optional dependencies
def load_json_safely(text):
    try:
        import json
        return json.loads(text)
    except ImportError:
        print("JSON module not available")
        return None

def enhanced_processing():
    try:
        from collections import Counter
        data = ['a', 'b', 'a', 'c', 'b', 'a']
        return Counter(data)
    except ImportError:
        # Fallback implementation
        counts = {}
        for item in ['a', 'b', 'a', 'c', 'b', 'a']:
            counts[item] = counts.get(item, 0) + 1
        return counts

# Test conditional imports
json_data = load_json_safely('{"name": "Alice"}')
counts = enhanced_processing()

print(f"JSON data: {json_data}")
print(f"Counts: {counts}")

🎯 Key Takeaways

🚀 What's Next?

Learn how to create virtual environments to manage project dependencies and avoid conflicts.

Continue to: Create Virtual Environments

Was this helpful?

😔Poor
🙁Fair
😊Good
😄Great
🤩Excellent