AiTechWorlds
AiTechWorlds
Python's module system lets you split code into reusable files and use thousands of third party libraries. Understanding it properly prevents the import errors and dependency conflicts that trip up beginners.
Any .py file is a module. You import it to use its contents.
# math_utils.py
PI = 3.14159265358979
def circle_area(radius):
return PI * radius ** 2
def circle_circumference(radius):
return 2 * PI * radius
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return circle_area(self.radius)
# main.py — in the same directory
import math_utils
print(math_utils.PI)
print(math_utils.circle_area(5))
# Selective import
from math_utils import circle_area, PI
# Alias import
import math_utils as mu
print(mu.circle_area(5))
# Import everything (usually avoid this — pollutes namespace)
from math_utils import *if __name__ == '__main__' PatternEvery module has a __name__ attribute. When run directly, __name__ == '__main__'. When imported, __name__ is the module name.
# calculator.py
def add(a, b):
return a + b
def multiply(a, b):
return a * b
def main():
print("Running calculator demo:")
print(f"3 + 4 = {add(3, 4)}")
print(f"3 × 4 = {multiply(3, 4)}")
if __name__ == '__main__':
# Only runs when this file is executed directly
# NOT when imported as a module
main()
# When you run: python calculator.py → main() executes
# When you run: import calculator → main() does NOT executeThis pattern is essential without it, importing your module would run all its code.
A package is a directory containing an __init__.py file (can be empty).
myapp/
├── __init__.py ← Makes myapp a package
├── config.py
├── models/
│ ├── __init__.py
│ ├── user.py
│ └── product.py
├── services/
│ ├── __init__.py
│ ├── auth.py
│ └── payment.py
└── utils/
├── __init__.py
└── helpers.py# Importing from packages
from myapp.models.user import User
from myapp.services.auth import authenticate
import myapp.config as config
# __init__.py can re-export for cleaner imports
# myapp/models/__init__.py
from .user import User
from .product import Product
# Now users can do:
from myapp.models import User, Product
# Instead of:
from myapp.models.user import User# myapp/services/auth.py
# Absolute import (always works, explicit)
from myapp.models.user import User
from myapp.config import SECRET_KEY
# Relative import (relative to current package)
from ..models.user import User # Go up one level, then into models
from ..config import SECRET_KEY # Go up one level, get config
from . import helpers # Import from same packageWithin a package, relative imports are common. In scripts, always use absolute imports.
# Install a package
pip install requests
# Install specific version
pip install requests==2.31.0
# Install minimum version
pip install "requests>=2.25.0"
# Upgrade a package
pip install --upgrade requests
# Uninstall
pip uninstall requests
# List installed packages
pip list
# Show package info and dependencies
pip show requests
# Save current environment's packages
pip freeze > requirements.txt
# Install from requirements file
pip install -r requirements.txt# requirements.txt
requests==2.31.0
pandas>=2.0.0
numpy>=1.24.0
scikit-learn>=1.3.0
python-dotenv==1.0.0
fastapi>=0.100.0
uvicorn[standard]>=0.23.0Always pin exact versions for production deployments. Use >= ranges for libraries you develop.
Python ships with an enormous standard library. Know what's available before installing third party packages:
# pathlib — file paths (covered in File I/O lesson)
# json — JSON parsing
# csv — CSV reading/writing
# datetime — date and time handling
# re — regular expressions
# math — mathematical functions
# random — random number generation
# collections — specialized containers
# itertools — functional tools for iterables
# functools — higher-order functions
# os, sys — OS interface and system info
# subprocess — run external commands
# logging — logging (covered in error handling)
# typing — type hints
# dataclasses — data classes
# abc — abstract base classes
# threading, asyncio — concurrency
# unittest — testing framework
# argparse — command-line arguments
# hashlib — hashing (SHA, MD5)
# base64 — encoding
# time, timeit — timing and performance
# Examples
from datetime import datetime, timedelta
import random
from collections import Counter, defaultdict, deque
import itertools
# Counter — count occurrences
words = "the quick brown fox jumps over the lazy dog".split()
word_count = Counter(words)
print(word_count.most_common(3)) # [('the', 2), ('quick', 1), ('brown', 1)]
# deque — efficient queue
queue = deque(maxlen=5) # Fixed-size queue
for i in range(10):
queue.append(i)
print(queue) # deque([5, 6, 7, 8, 9], maxlen=5)
# itertools
# Infinite counter
counter = itertools.count(10, 2) # 10, 12, 14, ...
# Combinations
for combo in itertools.combinations("ABC", 2):
print(combo) # ('A', 'B'), ('A', 'C'), ('B', 'C')
# Chain iterables
from itertools import chain
numbers = list(chain([1, 2], [3, 4], [5, 6]))
print(numbers) # [1, 2, 3, 4, 5, 6]# requests — HTTP requests
import requests
response = requests.get('https://api.github.com/users/python')
user = response.json()
# pandas — data analysis
import pandas as pd
df = pd.read_csv('data.csv')
print(df.head())
# numpy — numerical computing
import numpy as np
arr = np.array([1, 2, 3, 4, 5])
print(arr.mean(), arr.std())
# python-dotenv — load .env files
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv('API_KEY')
# rich — beautiful terminal output
from rich import print
from rich.table import Table
print("[bold green]Hello, World![/bold green]")
# pydantic — data validation
from pydantic import BaseModel, validator
class User(BaseModel):
name: str
age: int
email: strA directory without __init__.py is a namespace package useful for large codebases split across multiple directories.
org/
├── team_a/
│ └── module_a.py # No __init__.py needed!
└── team_b/
└── module_b.py
# From separate locations, both are importable
from org.team_a.module_a import something
from org.team_b.module_b import other_thingimport requests
import numpy as np
# Where is this module located?
print(requests.__file__) # Path to requests package directory
print(np.__file__) # Path to numpy
# What version?
print(requests.__version__)
print(np.__version__)
# What's in a module?
import math
print(dir(math)) # All attributes
# What does a function do?
help(math.log)
print(math.log.__doc__) # DocstringThe general principle: reach for the standard library first, add a third party package only when the standard library genuinely can't do the job, and always pin versions in requirements.txt so a fresh install reproduces the exact environment your code was tested in.
Next lesson: Virtual Environments & Project Setup keeping dependencies isolated.
Get this course's notes on Telegram!
Free cheat sheets, summaries & practice exercises