The Import System
As your programs grow beyond a single file, you need a way to organize code into reusable pieces. Python's module system lets you split code into separate files and import functionality from them. A module is simply a .py file. A package is a directory containing modules.
Python has three types of imports: the standard library (built-in modules like os, json, datetime), third-party packages (installed via pip, like requests, flask), and your own modules (your .py files).
Import Styles
Python offers several ways to import. Each has its place:
# Import the entire module
import math
print(math.pi) # 3.141592653589793
print(math.sqrt(16)) # 4.0
# Import specific items
from datetime import datetime, timedelta
now = datetime.now()
tomorrow = now + timedelta(days=1)
print(f"Now: {now:%Y-%m-%d}")
print(f"Tomorrow: {tomorrow:%Y-%m-%d}")
# Import with alias (common for long names)
import numpy as np
import pandas as pd
# Import everything (avoid this — pollutes namespace)
# from math import * # Bad practice!
3.141592653589793 4.0 Now: 2024-01-15 Tomorrow: 2024-01-16
Import Best Practices
Use import module for standard library modules (makes it clear where functions come from). Use from module import specific_thing when you use something frequently. Avoid from module import * — it makes code hard to read because you can't tell where names came from.
Creating Your Own Modules
Any Python file is a module. If you have mymath.py, you can import from it in another file:
# mymath.py
def add(a, b):
"""Add two numbers."""
return a + b
def multiply(a, b):
"""Multiply two numbers."""
return a * b
PI = 3.14159
# This block only runs when the file is executed directly,
# NOT when it's imported as a module
if __name__ == '__main__':
print(f"Testing: add(2, 3) = {add(2, 3)}")
print(f"Testing: multiply(4, 5) = {multiply(4, 5)}")
# main.py — using our module
from mymath import add, PI
result = add(10, 20)
print(f"{result}, PI = {PI}")
30, PI = 3.14159
if __name__ == '__main__': guard is essential. It lets your module file work both as a standalone script AND as an importable library. Without it, test code would run every time someone imports your module.Package Structure
A package is a directory that contains Python modules and a special __init__.py file (which can be empty). Packages let you organize related modules into a hierarchy:
myproject/
__init__.py # Makes this a package (can be empty)
core.py # Main functionality
utils.py # Helper functions
models/
__init__.py # Sub-package
user.py
product.py
# Importing from packages
from myproject.core import main_function
from myproject.models.user import User
from myproject.utils import format_date
pip and Virtual Environments
The Python Package Index (PyPI) hosts over 400,000 third-party packages. pip is the tool to install them. But there's a catch: if you install packages globally, different projects might need different versions of the same package. This is where virtual environments come in.
A virtual environment is an isolated Python installation for your project. Each project gets its own set of packages, avoiding version conflicts:
# Create a virtual environment
python3 -m venv myproject_env
# Activate it
source myproject_env/bin/activate # macOS/Linux
myproject_env\Scripts\activate # Windows
# Your prompt changes to show the active environment:
# (myproject_env) $
# Install packages (goes into this environment only)
pip install requests flask pandas
# See what's installed
pip list
# Save dependencies to a file
pip freeze > requirements.txt
# Someone else can recreate your environment:
pip install -r requirements.txt
# Deactivate when done
deactivate
⚠️ Common Mistake: Installing Packages Globally
Wrong:
pip install requests # Installs globally — affects ALL projects!
Why: Global installs cause version conflicts between projects. Project A needs requests==2.28 but Project B needs requests==2.31 — impossible with global installs.
Instead:
python3 -m venv venv
source venv/bin/activate
pip install requests # Isolated to this project
Essential Standard Library Modules
Python's standard library is famously comprehensive — "batteries included." Here are the modules you'll use most often:
# collections — specialized containers
from collections import Counter, defaultdict, namedtuple
words = "the cat sat on the mat the cat".split()
print(Counter(words)) # Count occurrences
# Counter({'the': 3, 'cat': 2, 'sat': 1, 'on': 1, 'mat': 1})
# defaultdict — dict with default values for missing keys
scores = defaultdict(list)
scores["Alice"].append(95)
scores["Alice"].append(87)
scores["Bob"].append(92)
print(dict(scores))
# {'Alice': [95, 87], 'Bob': [92]}
Counter({'the': 3, 'cat': 2, 'sat': 1, 'on': 1, 'mat': 1})
{'Alice': [95, 87], 'Bob': [92]}# functools — higher-order function utilities
from functools import lru_cache, reduce
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(50)) # Instant with caching!
# 12586269025
# os and pathlib — file system operations
from pathlib import Path
import os
print(os.getcwd()) # Current directory
print(Path.home()) # Home directory
print(list(Path(".").glob("*.py"))) # All .py files
| Module | Purpose | Key Functions |
|---|---|---|
os | Operating system interface | getcwd(), listdir(), environ |
sys | System-specific parameters | argv, path, exit() |
pathlib | Object-oriented paths | Path(), .glob(), .read_text() |
json | JSON encoding/decoding | dumps(), loads(), dump(), load() |
datetime | Date and time | datetime.now(), timedelta |
collections | Specialized containers | Counter, defaultdict, namedtuple |
functools | Function tools | lru_cache, partial, wraps |
itertools | Iterator utilities | chain, combinations, groupby |
re | Regular expressions | search(), findall(), sub() |
logging | Logging framework | getLogger(), basicConfig() |
🔍 Deep Dive: How Python Finds Modules
When you write import mymodule, Python searches these locations in order: (1) the current directory, (2) directories in the PYTHONPATH environment variable, (3) the standard library directory, (4) the site-packages directory (where pip installs). You can see the full search path with import sys; print(sys.path). If Python can't find the module in any of these locations, you get an ImportError.