Introduction to Python & Setup
What is Python?
Python is a high-level, interpreted, general-purpose programming language created by Guido van Rossum and first released in 1991. It emphasizes code readability and simplicity, using significant whitespace (indentation) to define code blocks instead of curly braces.
Python is one of the most widely used programming languages in the world, powering everything from web backends and data science pipelines to AI research and automation scripts.
Why Python?
- Easy to learn: Clean, English-like syntax lowers the barrier to entry.
- Versatile: Web dev, data science, ML/AI, automation, scripting, games.
- Huge ecosystem: 400,000+ packages on PyPI.
- Strong community: Massive documentation, tutorials, and forums.
- Cross-platform: Runs on Windows, macOS, Linux identically.
Installing Python
Download the latest version (3.x) from python.org. As of 2026, Python 3.12+ is recommended.
Windows
Download the installer from python.org and check "Add Python to PATH" during installation. Verify in Command Prompt:
python --version
# Expected: Python 3.12.x
macOS / Linux
macOS comes with Python 2 by default. Use Homebrew to install Python 3:
brew install python3 python3 --version
Your First Python Program
Open any text editor (VS Code is recommended) and create a file called hello.py:
# This is a comment — Python ignores it print("Hello, World!") print("Welcome to Python Mastery!")
Welcome to Python Mastery!
The Python Interactive Shell (REPL)
Python includes an interactive shell where you type code and see immediate results. Type
python (or python3) in your terminal:
>>> print("Hello") Hello >>> 2 + 3 5 >>> 10 / 3 3.3333333333333335 >>> exit() # exits the REPL
Using VS Code (Recommended IDE)
VS Code is a free, powerful editor perfect for Python development. Install the Python extension by Microsoft from the Extensions panel. It provides:
- Syntax highlighting and IntelliSense (auto-complete)
- Integrated debugger
- Built-in terminal
- Linting and formatting (via Pylint, Black)
Understanding Python Syntax Basics
Indentation is mandatory
Python uses indentation (4 spaces per level by convention) instead of curly braces to define code structure:
if True: print("This is indented — it's inside the if block") print("So is this") print("This is outside — runs regardless")
Comments
# Single-line comment — Python ignores this """ Multi-line string used as a docstring/comment block. Often used to document functions and classes. """ x = 5 # Inline comment
How Python Runs Code
Python is an interpreted language. When you run python script.py, the Python interpreter
reads your source code line by line, converts it to bytecode (.pyc files in
__pycache__), and executes it via the Python Virtual Machine (PVM).
Create a file called intro.py. Write a program that prints your name, your age, and your
country on three separate lines. Run it from the terminal.
Open the Python REPL and compute: what is 17 multiplied by 23? What is 2 to the power of 10? Use Python as a calculator.
Variables & Data Types
Variables
A variable is a named reference to a value stored in memory. In Python, you create variables simply by assigning a value — no type declaration needed.
name = "Alice" age = 25 height = 5.6 is_student = True print(name, age, height, is_student)
Naming Rules
- Must start with a letter or underscore (
_) - Can contain letters, numbers, underscores — no spaces or special chars
- Case-sensitive:
Name≠name - Cannot be a Python keyword (
if,for,class, etc.)
user_name,
total_price. Use UPPER_CASE for constants: MAX_SIZE = 100.
Core Data Types
| Type | Example | Description |
|---|---|---|
int |
42, -7, 0 |
Whole numbers (unlimited size) |
float |
3.14, -0.5 |
Decimal / floating point numbers |
str |
"hello", 'world' |
Text (sequence of characters) |
bool |
True, False |
Boolean (logical True/False) |
NoneType |
None |
Represents the absence of a value |
Integers
x = 42 y = -100 big = 1_000_000 # underscores for readability binary = 0b1010 # binary literal → 10 hexval = 0xFF # hexadecimal → 255 print(type(x)) # <class 'int'> print(big) # 1000000
Floats
pi = 3.14159 sci = 1.5e10 # scientific notation: 15000000000.0 neg = -2.7 print(type(pi)) # <class 'float'> # Floating point precision caveat: print(0.1 + 0.2) # 0.30000000000000004 (IEEE 754)
decimal module.
Strings
s1 = "Hello, World!" s2 = 'Single quotes work too' s3 = """Triple-quoted strings span multiple lines""" # Escape sequences s4 = "Line 1\nLine 2" # \n = newline s5 = "Tab\there" # \t = tab s6 = "Quote: \"hi\"" # \" = literal quote # f-strings (Python 3.6+) — the preferred way name = "Bob" age = 30 msg = f"My name is {name} and I am {age} years old" print(msg)
Booleans
t = True f = False print(type(t)) # <class 'bool'> print(True + True) # 2 — bools are ints (True=1, False=0) # Truthiness — these evaluate as False: # 0, 0.0, "", [], {}, None print(bool(0)) # False print(bool("")) # False print(bool(42)) # True
Type Conversion
# Explicit conversion (casting) x = int("42") # str → int: 42 y = float("3.14") # str → float: 3.14 z = str(100) # int → str: "100" b = bool(1) # int → bool: True # Getting user input (always returns str) name = input("Enter your name: ") age = int(input("Enter your age: ")) # must cast! print(f"Hello {name}, you are {age}")
Dynamic Typing & type()
Python is dynamically typed — the same variable can hold different types over its lifetime:
x = 10 print(type(x)) # <class 'int'> x = "hello" print(type(x)) # <class 'str'> x = [1, 2, 3] print(type(x)) # <class 'list'>
Write a program that asks the user for their name and birth year, then calculates and prints their approximate age with an f-string.
Create variables of each core type (int, float, str, bool, None). Use type() to print
each one's type.
Operators & Expressions
Arithmetic Operators
a, b = 17, 5 print(a + b) # Addition: 22 print(a - b) # Subtraction: 12 print(a * b) # Multiplication: 85 print(a / b) # Division: 3.4 (always float!) print(a // b) # Floor division: 3 (truncates decimal) print(a % b) # Modulo: 2 (remainder) print(a ** b) # Exponentiation: 1419857
Comparison Operators
Comparison operators always return a boolean (True or False).
x = 10 print(x == 10) # Equal: True print(x != 5) # Not equal: True print(x > 8) # Greater than: True print(x < 8) # Less than: False print(x >= 10) # Greater or equal: True print(x <= 9) # Less or equal: False # Chained comparisons (Pythonic) age = 20 print(18 <= age <= 65) # True — very readable!
Logical Operators
a = True b = False print(a and b) # False — both must be True print(a or b) # True — at least one True print(not a) # False — flips the boolean # Short-circuit evaluation x = 0 result = x or "default" print(result) # "default" — x is falsy, so "or" returns right side name = "Alice" greeting = name and f"Hello, {name}" print(greeting) # "Hello, Alice" — name is truthy
Assignment Operators
x = 10 x += 5 # x = x + 5 → 15 x -= 3 # x = x - 3 → 12 x *= 2 # x = x * 2 → 24 x //= 4 # x = x // 4 → 6 x **= 2 # x = x ** 2 → 36 print(x) # 36 # Multiple assignment a, b, c = 1, 2, 3 x = y = z = 0 # all set to 0 # Swap variables (Pythonic!) a, b = b, a
Identity & Membership Operators
# Identity: is / is not (checks memory identity) x = [1, 2, 3] y = x z = [1, 2, 3] print(x is y) # True — same object in memory print(x is z) # False — same values, different objects print(x == z) # True — same values # Membership: in / not in fruits = ["apple", "banana", "cherry"] print("banana" in fruits) # True print("grape" not in fruits) # True
Operator Precedence
Operators follow a defined precedence order (highest first): ** → unary -/+ →
* / // % → + - → comparisons → not → and →
or. Use parentheses to be explicit:
print(2 + 3 * 4) # 14 (multiplication first) print((2 + 3) * 4) # 20 (parentheses override) print(2 ** 3 ** 2) # 512 (** is right-associative: 2**(3**2))
Write a program that takes a number from the user and determines whether it is even or odd using the modulo operator. Print an appropriate message.
Calculate the area and circumference of a circle given a radius entered by the user. Use
pi = 3.14159.
Control Flow: if / elif / else
The if Statement
Conditional statements allow your program to make decisions and execute different code based on conditions.
temperature = 35 if temperature > 30: print("It's hot outside!") print("Stay hydrated.")
Stay hydrated.
if / else
age = 16 if age >= 18: print("You can vote.") else: years_left = 18 - age print(f"You need to wait {years_left} more years.")
if / elif / else
score = 78 if score >= 90: grade = "A" elif score >= 80: grade = "B" elif score >= 70: grade = "C" elif score >= 60: grade = "D" else: grade = "F" print(f"Score: {score} → Grade: {grade}")
Nested if Statements
username = "admin" password = "secret123" if username == "admin": if password == "secret123": print("Access granted!") else: print("Wrong password.") else: print("Unknown user.")
Ternary (Conditional Expression)
A one-line if/else for simple assignments:
age = 20 status = "adult" if age >= 18 else "minor" print(status) # adult # Equivalent to: if age >= 18: status = "adult" else: status = "minor"
match / case (Python 3.10+)
Python's structural pattern matching — similar to switch/case in other languages, but far more powerful:
command = "quit" match command: case "start": print("Starting...") case "stop" | "quit": print("Stopping.") case _: print("Unknown command")
Ask the user for their weight (kg) and height (m). Compute BMI = weight / height². Then categorize: Underweight (<18.5), Normal (18.5–24.9), Overweight (25–29.9), Obese (≥30).
Ask the user for a year. Determine if it's a leap year. A year is leap if: divisible by 4 AND (not divisible by 100 OR divisible by 400).
Loops: for & while
The for Loop
Python's for loop iterates over any iterable (list, string, range, etc.).
fruits = ["apple", "banana", "cherry"] for fruit in fruits: print(f"I like {fruit}") # Iterating a string for char in "Python": print(char, end="-") # P-y-t-h-o-n-
range()
# range(stop) for i in range(5): print(i, end=" ") # 0 1 2 3 4 # range(start, stop) for i in range(1, 6): print(i, end=" ") # 1 2 3 4 5 # range(start, stop, step) for i in range(0, 20, 5): print(i, end=" ") # 0 5 10 15 # Counting backwards for i in range(10, 0, -1): print(i, end=" ") # 10 9 8 7 6 5 4 3 2 1
enumerate() and zip()
# enumerate gives index + value animals = ["cat", "dog", "bird"] for i, animal in enumerate(animals, start=1): print(f"{i}. {animal}") # 1. cat 2. dog 3. bird # zip iterates multiple lists simultaneously names = ["Alice", "Bob", "Carol"] scores = [95, 87, 92] for name, score in zip(names, scores): print(f"{name}: {score}")
The while Loop
count = 0 while count < 5: print(f"Count: {count}") count += 1 # Interactive while loop while True: answer = input("Say 'quit' to exit: ") if answer == "quit": break print(f"You typed: {answer}")
break, continue, pass
# break — exits the loop immediately for i in range(10): if i == 5: break print(i, end=" ") # 0 1 2 3 4 # continue — skips current iteration for i in range(10): if i % 2 == 0: continue # skip even numbers print(i, end=" ") # 1 3 5 7 9 # pass — does nothing, placeholder for i in range(3): pass # useful for empty loops/stubs
List Comprehensions (Preview)
A concise way to create lists using a for loop in a single line:
# Standard way squares = [] for i in range(1, 6): squares.append(i ** 2) # List comprehension — same thing, one line! squares = [i ** 2 for i in range(1, 6)] print(squares) # [1, 4, 9, 16, 25] # With a filter evens = [x for x in range(20) if x % 2 == 0] print(evens) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Use nested for loops to print the multiplication table from 1×1 to 10×10.
Pick a secret number (e.g., 42). Use a while loop to keep asking the user to guess. Print "Too high", "Too low", or "Correct!" and track how many guesses they took.
Functions
Defining and Calling Functions
Functions are reusable blocks of code that perform a specific task. Use the def keyword:
def greet(): """Prints a greeting message.""" print("Hello! Welcome to Python.") greet() # Call the function greet() # Can be called many times
Parameters and Arguments
def greet(name, greeting="Hello"): # default parameter print(f"{greeting}, {name}!") greet("Alice") # Hello, Alice! greet("Bob", "Good morning") # Good morning, Bob! greet(greeting="Hi", name="Carol") # keyword args
Return Values
def add(a, b): return a + b result = add(3, 5) print(result) # 8 # Return multiple values (as a tuple) def min_max(numbers): return min(numbers), max(numbers) lo, hi = min_max([3, 1, 7, 4, 9]) print(f"Min: {lo}, Max: {hi}") # Min: 1, Max: 9
*args and **kwargs
# *args: variable positional arguments (tuple) def total(*numbers): return sum(numbers) print(total(1, 2, 3)) # 6 print(total(10, 20, 30, 40)) # 100 # **kwargs: variable keyword arguments (dict) def describe(**info): for key, value in info.items(): print(f"{key}: {value}") describe(name="Alice", age=30, city="Paris")
Scope: Local vs Global
x = 10 # global variable def my_func(): y = 20 # local — only exists inside function print(x) # can READ global print(y) my_func() # print(y) # NameError — y doesn't exist here # To MODIFY a global inside a function: count = 0 def increment(): global count count += 1 increment() print(count) # 1
Lambda Functions
Anonymous one-line functions using the lambda keyword:
# lambda arguments: expression square = lambda x: x ** 2 print(square(5)) # 25 add = lambda a, b: a + b print(add(3, 4)) # 7 # Most useful with map(), filter(), sorted() numbers = [5, 2, 8, 1, 9] sorted_nums = sorted(numbers, key=lambda x: -x) print(sorted_nums) # [9, 8, 5, 2, 1]
Recursion
def factorial(n): """Returns n! recursively.""" if n <= 1: return 1 return n * factorial(n - 1) print(factorial(5)) # 120 (5*4*3*2*1) print(factorial(10)) # 3628800
sys.setrecursionlimit().
Write a function is_palindrome(s) that returns True if the string
s reads the same forwards and backwards (e.g., "racecar" → True).
Write a recursive function fibonacci(n) that returns the nth Fibonacci number. Then
optimise it with a cache (hint: look up functools.lru_cache).
Data Structures
Lists
Lists are ordered, mutable, allow duplicates. Defined with square brackets.
fruits = ["apple", "banana", "cherry"] # Indexing (0-based, negative counts from end) print(fruits[0]) # apple print(fruits[-1]) # cherry # Slicing [start:stop:step] print(fruits[0:2]) # ['apple', 'banana'] print(fruits[::-1]) # reversed: ['cherry', 'banana', 'apple'] # Modifying fruits.append("date") # add to end fruits.insert(1, "avocado") # insert at index 1 fruits.remove("banana") # remove first occurrence popped = fruits.pop() # remove and return last item # Useful methods nums = [3, 1, 4, 1, 5, 9] nums.sort() # in-place sort print(sorted(nums)) # returns new sorted list print(len(nums)) # 6 print(nums.count(1)) # 2
Tuples
Tuples are ordered, immutable. Use parentheses. Great for fixed data like coordinates.
point = (3, 7) rgb = (255, 128, 0) x, y = point # tuple unpacking r, g, b = rgb # Tuples are faster and use less memory than lists # Use tuples for data that shouldn't change # point[0] = 5 # TypeError: tuple is immutable single = (42,) # single-element tuple needs trailing comma
Dictionaries
Dictionaries store key-value pairs. Keys must be unique and hashable. Python 3.7+ preserves insertion order.
person = {
"name": "Alice",
"age": 30,
"city": "London"
}
# Access
print(person["name"]) # Alice
print(person.get("phone", "N/A")) # N/A (safe get)
# Modify
person["age"] = 31
person["email"] = "alice@example.com"
del person["city"]
# Iterate
for key, value in person.items():
print(f"{key}: {value}")
# Dictionary comprehension
squares = {x: x**2 for x in range(1, 6)}
# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
Sets
Sets are unordered collections of unique elements. Perfect for deduplication and set math.
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
print(a | b) # Union: {1, 2, 3, 4, 5, 6}
print(a & b) # Intersection: {3, 4}
print(a - b) # Difference: {1, 2}
print(a ^ b) # Sym. diff: {1, 2, 5, 6}
# Deduplicate a list
nums = [1, 2, 2, 3, 3, 3]
unique = list(set(nums)) # [1, 2, 3]
s = set() # empty set (NOT {} — that's a dict!)
s.add(42)
Choosing the Right Structure
| Structure | Ordered | Mutable | Duplicates | Use When |
|---|---|---|---|---|
| list | ✅ | ✅ | ✅ | Ordered, changeable collection |
| tuple | ✅ | ❌ | ✅ | Fixed data, dict keys, unpacking |
| dict | ✅ | ✅ | keys: ❌ | Key-value lookup |
| set | ❌ | ✅ | ❌ | Uniqueness, set operations |
Write a program that takes a sentence from the user and prints how many times each word appears, sorted by frequency (most common first).
Build a simple phone book using a dictionary. Allow the user to: add a contact, look up a number, delete a contact, and list all contacts.
Strings In Depth
String Indexing & Slicing
s = "Hello, World!" print(s[0]) # H print(s[-1]) # ! print(s[7:12]) # World print(s[::2]) # Hlo ol! print(s[::-1]) # !dlroW ,olleH (reversed) print(len(s)) # 13
Essential String Methods
s = " Hello, World! " print(s.strip()) # "Hello, World!" (removes whitespace) print(s.upper()) # " HELLO, WORLD! " print(s.lower()) # " hello, world! " print(s.title()) # " Hello, World! " t = "Hello, World!" print(t.replace("World", "Python")) # Hello, Python! print(t.split(", ")) # ['Hello', 'World!'] print(t.startswith("Hello")) # True print(t.endswith("!")) # True print(t.find("World")) # 7 print(t.count("l")) # 3 words = ["one", "two", "three"] print(" | ".join(words)) # one | two | three
f-Strings (Formatted String Literals)
name = "Alice" score = 98.5678 items = 1000000 # Basic print(f"Name: {name}") # Number formatting print(f"Score: {score:.2f}") # 2 decimal places print(f"Items: {items:,}") # thousands separator print(f"Score: {score:10.2f}") # width 10, right-aligned # Padding and alignment print(f"{'Left':<10}") # left-align in 10 chars print(f"{'Right':>10}") # right-align print(f"{'Center':^10}") # center # Expressions in f-strings print(f"2 + 2 = {2 + 2}") print(f"Upper: {name.upper()}")
Raw Strings & Bytes
# Raw strings: backslash is literal (useful for regex and paths) path = r"C:\Users\Alice\Documents" print(path) # C:\Users\Alice\Documents # Bytes: prefix b"" b = b"Hello" print(type(b)) # <class 'bytes'> print(b.decode()) # "Hello" — bytes to str print("Hello".encode()) # b'Hello' — str to bytes
Regular Expressions (Intro)
import re text = "My email is alice@example.com and bob@test.org" # Find all email addresses emails = re.findall(r'\b[\w.+-]+@[\w-]+\.\w+\b', text) print(emails) # ['alice@example.com', 'bob@test.org'] # Check if a string is a valid phone number phone = "123-456-7890" match = re.match(r'^\d{3}-\d{3}-\d{4}$', phone) print(bool(match)) # True
Write a function that takes a sentence and returns: word count, character count (no spaces), most common letter, and whether it's a palindrome (ignoring spaces and case).
Object-Oriented Programming
Classes and Objects
OOP is a programming paradigm that organises code around objects — bundles of data (attributes) and behaviour (methods).
class Dog: """A simple Dog class.""" species = "Canis lupus familiaris" # class variable def __init__(self, name, age): # constructor self.name = name # instance variable self.age = age def bark(self): print(f"{self.name} says: Woof!") def __str__(self): # string representation return f"Dog({self.name}, {self.age})" # Creating instances rex = Dog("Rex", 3) luna = Dog("Luna", 5) rex.bark() # Rex says: Woof! print(luna) # Dog(Luna, 5) print(rex.species) # Canis lupus familiaris
Inheritance
class Animal: def __init__(self, name): self.name = name def speak(self): raise NotImplementedError def __str__(self): return f"{self.__class__.__name__}({self.name})" class Cat(Animal): # inherits from Animal def speak(self): return f"{self.name} says: Meow!" class Dog(Animal): def __init__(self, name, breed): super().__init__(name) # call parent __init__ self.breed = breed def speak(self): return f"{self.name} ({self.breed}) says: Woof!" animals = [Cat("Whiskers"), Dog("Rex", "Labrador")] for animal in animals: print(animal.speak()) # polymorphism!
Encapsulation & Properties
class BankAccount: def __init__(self, owner, balance=0): self.owner = owner self._balance = balance # _ = convention: "private" @property def balance(self): return self._balance @balance.setter def balance(self, amount): if amount < 0: raise ValueError("Balance cannot be negative") self._balance = amount def deposit(self, amount): self._balance += amount def withdraw(self, amount): if amount > self._balance: raise ValueError("Insufficient funds") self._balance -= amount acc = BankAccount("Alice", 1000) acc.deposit(500) print(acc.balance) # 1500
Dunder (Magic) Methods
class Vector: def __init__(self, x, y): self.x, self.y = x, y def __add__(self, other): # + return Vector(self.x + other.x, self.y + other.y) def __len__(self): # len() return 2 def __repr__(self): # repr() return f"Vector({self.x}, {self.y})" v1 = Vector(1, 2) v2 = Vector(3, 4) print(v1 + v2) # Vector(4, 6) print(len(v1)) # 2
Create a Book class with title, author, and year. Create a Library class
that holds a list of books, with methods: add_book(), remove_book(),
search_by_author(), and list_all().
File I/O & Exception Handling
Reading & Writing Files
# Writing a file with open("greetings.txt", "w") as f: f.write("Hello, World!\n") f.write("Python is awesome!\n") # Reading entire file with open("greetings.txt", "r") as f: content = f.read() print(content) # Reading line by line with open("greetings.txt", "r") as f: for line in f: print(line.strip()) # Appending to a file with open("greetings.txt", "a") as f: f.write("Added a new line!\n")
with statement (context manager) automatically closes the file even if an error occurs.
Never use f = open(...) without closing it.
Working with CSV and JSON
import csv import json # CSV writing with open("data.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["Name", "Score"]) writer.writerow(["Alice", 95]) # CSV reading with open("data.csv") as f: for row in csv.DictReader(f): print(row) # {'Name': 'Alice', 'Score': '95'} # JSON serialization data = {"name": "Alice", "scores": [95, 87, 92]} with open("data.json", "w") as f: json.dump(data, f, indent=2) with open("data.json") as f: loaded = json.load(f) print(loaded["name"]) # Alice
Exception Handling
# try / except / else / finally try: num = int(input("Enter a number: ")) result = 100 / num except ValueError: print("That's not a valid number!") except ZeroDivisionError: print("Can't divide by zero!") except Exception as e: print(f"Unexpected error: {e}") else: print(f"Result: {result}") # runs only if no exception finally: print("This always runs") # cleanup code
Raising Exceptions & Custom Exceptions
class InsufficientFundsError(Exception): """Raised when a withdrawal exceeds the balance.""" def __init__(self, amount, balance): self.amount = amount self.balance = balance super().__init__( f"Cannot withdraw {amount}; balance is {balance}" ) def withdraw(balance, amount): if amount > balance: raise InsufficientFundsError(amount, balance) return balance - amount try: withdraw(100, 200) except InsufficientFundsError as e: print(e) # Cannot withdraw 200; balance is 100
Write a function read_file(path) that reads a file and returns its contents. Handle
FileNotFoundError and PermissionError gracefully with informative
messages. Test it with valid and invalid paths.
Modules, Packages & Popular Libraries
Importing Modules
import math import os import sys from datetime import datetime, timedelta from random import randint, choice import json as j # alias print(math.pi) # 3.141592... print(math.sqrt(16)) # 4.0 print(math.floor(3.9)) # 3 now = datetime.now() print(now.strftime("%Y-%m-%d %H:%M")) tomorrow = now + timedelta(days=1) print(tomorrow)
Creating Your Own Module
"""Custom math utilities module.""" def is_prime(n): if n < 2: return False for i in range(2, int(n**0.5) + 1): if n % i == 0: return False return True def celsius_to_fahrenheit(c): return c * 9/5 + 32 PI = 3.14159265358979
from mathutils import is_prime, celsius_to_fahrenheit print(is_prime(17)) # True print(celsius_to_fahrenheit(100)) # 212.0
Installing Packages with pip
pip install requests # HTTP requests pip install numpy # numerical computing pip install pandas # data analysis pip install matplotlib # plotting pip install flask # web framework pip install pytest # testing pip list # see installed packages pip freeze > requirements.txt # export dependencies pip install -r requirements.txt # install from file
Key Standard Library Modules
| Module | Purpose | Key Functions |
|---|---|---|
os |
OS interaction | getcwd, listdir, path.join, mkdir |
sys |
System-specific | argv, exit, path, version |
math |
Math functions | sqrt, ceil, floor, log, sin |
random |
Randomness | randint, choice, shuffle, sample |
datetime |
Date/time | now, strftime, timedelta |
collections |
Advanced containers | Counter, defaultdict, deque |
itertools |
Iterators | chain, product, combinations |
pathlib |
File paths | Path, glob, mkdir, read_text |
Virtual Environments
# Create a virtual environment python -m venv venv # Activate (macOS/Linux) source venv/bin/activate # Activate (Windows) venv\Scripts\activate # Deactivate deactivate
Use the random module to build a quiz that picks 5 random questions from a list of 10
Q&A pairs, shuffles the answer options, and keeps score.
Capstone Project: Task Manager CLI
Congratulations on reaching the final lecture! We'll now build a fully functional command-line task manager that ties together everything covered in this course.
Project Features
- Add, view, complete, and delete tasks
- Persist tasks to a JSON file (survives program restarts)
- Filter tasks by status (all / pending / done)
- OOP design with a
Taskclass andTaskManagerclass - Input validation and exception handling
- Colorized CLI output
Project Structure
task_manager/ ├── main.py # entry point & CLI loop ├── task.py # Task and TaskManager classes ├── storage.py # JSON file persistence └── tasks.json # auto-created data file
task.py — Core Classes
from datetime import datetime import uuid class Task: """Represents a single task.""" def __init__(self, title, priority="medium"): self.id = str(uuid.uuid4())[:8] self.title = title self.priority = priority self.done = False self.created = datetime.now().isoformat() def complete(self): self.done = True def to_dict(self): return vars(self) @classmethod def from_dict(cls, data): t = cls(data["title"], data["priority"]) t.id = data["id"] t.done = data["done"] t.created = data["created"] return t def __str__(self): status = "✓" if self.done else "○" return f"[{status}] {self.id} | {self.title} ({self.priority})" class TaskManager: """Manages a collection of tasks.""" def __init__(self): self.tasks = [] def add(self, title, priority="medium"): task = Task(title, priority) self.tasks.append(task) return task def complete(self, task_id): task = self._find(task_id) if task: task.complete() return task raise ValueError(f"Task {task_id} not found") def delete(self, task_id): task = self._find(task_id) if task: self.tasks.remove(task) else: raise ValueError(f"Task {task_id} not found") def filter(self, status="all"): if status == "done": return [t for t in self.tasks if t.done] elif status == "pending": return [t for t in self.tasks if not t.done] return self.tasks def _find(self, task_id): return next((t for t in self.tasks if t.id == task_id), None)
storage.py — JSON Persistence
import json from pathlib import Path from task import Task FILE = Path("tasks.json") def load(): if not FILE.exists(): return [] with FILE.open() as f: return [Task.from_dict(d) for d in json.load(f)] def save(tasks): with FILE.open("w") as f: json.dump([t.to_dict() for t in tasks], f, indent=2)
main.py — CLI Entry Point
from task import TaskManager import storage def show_menu(): print("\n── Task Manager ──────────────") print(" 1. Add task") print(" 2. List tasks") print(" 3. Complete task") print(" 4. Delete task") print(" 5. Quit") print("──────────────────────────────") def main(): mgr = TaskManager() mgr.tasks = storage.load() while True: show_menu() choice = input("Choice: ").strip() if choice == "1": title = input("Task title: ") priority = input("Priority (low/medium/high): ") or "medium" task = mgr.add(title, priority) print(f"Added: {task}") elif choice == "2": filt = input("Filter (all/pending/done): ") or "all" tasks = mgr.filter(filt) if not tasks: print("No tasks found.") else: for t in tasks: print(" ", t) elif choice == "3": tid = input("Task ID to complete: ") try: t = mgr.complete(tid) print(f"Completed: {t}") except ValueError as e: print(f"Error: {e}") elif choice == "4": tid = input("Task ID to delete: ") try: mgr.delete(tid) print("Deleted.") except ValueError as e: print(f"Error: {e}") elif choice == "5": storage.save(mgr.tasks) print("Goodbye! Tasks saved.") break storage.save(mgr.tasks) # auto-save after every action if __name__ == "__main__": main()
What You've Learned
This capstone project applied every major concept from the course:
- Variables & types — task attributes, status flags
- Control flow — if/elif menu dispatch
- Loops —
while TrueCLI loop, list comprehensions - Functions — helper functions, class methods
- Data structures — list of Task objects, dict serialization
- OOP — Task and TaskManager classes, class methods
- File I/O & JSON — persistent storage
- Exception handling — try/except for user errors
- Modules — splitting code across files
You've completed the core Python curriculum! Consider exploring:
- Web development — Flask or FastAPI
- Data science — NumPy, Pandas, Matplotlib
- Machine learning — scikit-learn, TensorFlow, PyTorch
- Automation — Selenium, requests, BeautifulSoup
- Testing — pytest, unittest
- Async programming — asyncio, aiohttp
Add these features to the task manager: (1) due dates for tasks, (2) search tasks by keyword, (3) export tasks to a CSV report, (4) a statistics command showing counts per priority and completion rate.