PY

Python Fundamentals

18 lessons

Progress0%
1. Introduction to Python
1What is Python?2Setting Up Python
2. Variables and Data Types
1Variables in Python2Data Types
3. Control Flow
Conditional StatementsLoops
4. Functions
Function Basics
5. Data Structures
Lists Deep DiveTuples & SetsDictionaries & Comprehensions
6. Advanced Functions
Closures & Higher-Order FunctionsDecorators & Lambda
7. Object-Oriented Python
Classes & InstancesInheritance & Dunder Methods
8. Exception Handling
try / except / finallyCustom Exceptions & Context Managers
9. Modules & File I/O
Modules & PackagesFile I/O & JSON
All Tutorials
PythonModules & File I/O
Lesson 17 of 18 min
Chapter 9 · Lesson 1

Modules & Packages

Modules & Packages

A module is simply a .py file. A package is a directory containing an __init__.py file (which may be empty) plus one or more modules. Python's module system lets you organise, reuse, and distribute code.

Importing

python
import math                        # import the whole module
from math import sqrt, pi          # import specific names
from math import sqrt as square_root  # rename on import
import numpy as np                 # common alias pattern

Prefer explicit imports (from module import name) over wildcard imports (from module import *) — wildcards pollute the namespace and make it hard to trace where names come from.

name == "main"

Every module has a __name__ attribute. When a script is run directly, __name__ equals "__main__". When imported, it equals the module's file name. This idiom protects code that should only run as a script:

python
# mymodule.py
def add(a, b):
    return a + b

if __name__ == "__main__":
    print(add(2, 3))   # only runs when executed directly

Creating a Package

code
mypackage/
    __init__.py        # marks the directory as a package
    utils.py
    models.py
python
from mypackage import utils
from mypackage.models import User

__init__.py can re-export names for a cleaner public API:

python
# mypackage/__init__.py
from .utils import helper_function
from .models import User

Key Standard Library Modules

ModulePurpose
osOS interaction: paths, env vars, processes
sysInterpreter state: argv, path, exit
mathMathematical functions and constants
randomPseudo-random numbers
datetimeDates and times
pathlibObject-oriented filesystem paths
collectionsSpecialised containers (deque, Counter, defaultdict)
itertoolsIterator building blocks
functoolsHigher-order functions (reduce, lru_cache, wraps)
reRegular expressions
jsonJSON serialisation
csvCSV file reading/writing
loggingFlexible logging
unittestTest framework

Code Examples

math, random, and datetimepython
import math
import random
from datetime import datetime, timedelta

# math module
print("pi:", math.pi)
print("sqrt(144):", math.sqrt(144))
print("ceil(4.2):", math.ceil(4.2))
print("factorial(6):", math.factorial(6))
print("log2(1024):", math.log2(1024))

# random module
random.seed(42)
print("\nRandom int (1-10):", random.randint(1, 10))
print("Random choice:", random.choice(["apple", "banana", "cherry"]))
nums = list(range(1, 11))
random.shuffle(nums)
print("Shuffled:", nums)

# datetime module
now = datetime(2024, 6, 15, 9, 30)
print("\nNow:", now.strftime("%Y-%m-%d %H:%M"))
future = now + timedelta(days=30, hours=2)
print("In 30 days:", future.strftime("%Y-%m-%d %H:%M"))

math provides precise mathematical functions. random.seed() makes results reproducible — essential for testing. datetime objects support arithmetic via timedelta, making date calculations natural.

os and syspython
import os
import sys

# os — operating system interface
cwd = os.getcwd()
print("Current directory:", cwd)

# Environment variables
path = os.environ.get("PATH", "not set")
print("PATH is set:", path != "not set")

# os.path utilities
sample = "/home/user/documents/report.txt"
print("Dirname: ", os.path.dirname(sample))
print("Basename:", os.path.basename(sample))
print("Splitext:", os.path.splitext(sample))
print("Join:    ", os.path.join("/home/user", "docs", "file.txt"))

# sys — interpreter info
print("\nPython version:", sys.version[:6])
print("Platform:", sys.platform)
print("Executable:", sys.executable[:30], "...")

os.path functions manipulate path strings without touching the filesystem. os.environ provides a dict-like interface to environment variables. sys gives access to interpreter internals like the Python version, loaded modules, and the command-line arguments.

collections Modulepython
from collections import Counter, defaultdict, deque

# Counter — count occurrences
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
counter = Counter(words)
print("Counts:", dict(counter))
print("Top 2:", counter.most_common(2))

# defaultdict — dict with automatic default values
graph = defaultdict(list)
edges = [("A", "B"), ("A", "C"), ("B", "D"), ("C", "D")]
for src, dst in edges:
    graph[src].append(dst)
print("\nGraph:", dict(graph))

# deque — efficient double-ended queue
dq = deque([1, 2, 3], maxlen=5)
dq.appendleft(0)   # O(1) left append
dq.append(4)       # O(1) right append
print("\nDeque:", dq)
dq.rotate(2)       # rotate right by 2
print("Rotated:", dq)

Counter is great for frequency analysis. defaultdict eliminates KeyError when building nested structures. deque with maxlen acts as a circular buffer, dropping the oldest item when full. All three are O(1) for their primary operations.

Quick Quiz

1. What is the purpose of if __name__ == '__main__':?

2. What makes a directory a Python package?

3. Which collections type is best for counting occurrences of items?

Was this lesson helpful?

PreviousNext