Python Comprehensive Guide
Python Comprehensive Guide
■ Python
Comprehensive
Programming Guide
From First Print Statement to Recursion & OOP
Sections 1 – 18 · CS Definitions · Code Examples · All Skill Levels
Covers: Basics · Data Types · Loops · Scope · Operations · Methods · Input
Conditionals · F-strings · Random · Algorithms · Files · Arrays
Lists/Tuples/Dicts · OOP · Big 4 · Sorting & Searching · Recursion
—1—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Table of Contents
Section 1 · Basics
print, output, language fundamentals
Section 2 · Data Types & Type Casting
int, float, bool, str, None + casting
Section 3 · Loops
for, while, range, for-each, break/continue
Section 4 · Nested Structures & Scope
nesting, LEGB, global/nonlocal
Section 5 · Operations
arithmetic, math library, concatenation, shorthand
Section 6 · Methods & Parameters
functions, params, arguments, overloading
Section 7 · Input
input(), tokens, parsing, type conversion
Section 8 · Conditionals
if / elif / else, ternary
Section 9 · F-strings & Print Formatting
f-strings, format specs, print options
Section 10 · Random
random module, seeding, distributions
Section 11 · Algorithm Principles
Boolean zen, assertions, lookahead, fencepost, DeMorgan
Section 12 · File Processing
reading, writing, with-blocks, token/line based
Section 13 · Arrays (Lists as Arrays)
properties, value vs reference, 2-D arrays
Section 14 · Lists, Tuples & Dictionaries
collections deep dive, comprehensions
Section 15 · Objects & Classes
classes, __init__, static vs instance, state/behavior
Section 16 · The Big 4
abstraction, inheritance, polymorphism, encapsulation
Section 17 · Sorting & Searching
built-ins, algorithms, binary search
Section 18 · Recursion
base case, call stack, classic problems
—2—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
—3—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 1 Basics
print statements · output · what is Python?
What is Python?
Python is a high-level, interpreted, dynamically-typed, general-purpose programming language created by
Guido van Rossum and first released in 1991. It emphasises code readability — its syntax is designed to be
close to plain English — making it an excellent first language and a powerful tool for professionals.
Key CS Definitions
Programming Language
A formal set of rules (syntax) and meanings (semantics) used to instruct a computer.
Interpreted Language
Code is executed line-by-line by an interpreter at runtime, rather than compiled to machine code ahead of
time. Python uses CPython (the standard interpreter).
High-Level Language
Abstracts away hardware details (memory addresses, CPU registers). Opposite of assembly.
Dynamically Typed
Variable types are determined at runtime, not declared at compile-time. A variable can hold an int, then
later hold a string.
Syntax
The set of rules governing how programs must be written to be valid.
Semantics
The meaning of syntactically valid code — what it actually does.
Statement
A single instruction that Python can execute (e.g., a print call, an assignment).
Expression
A combination of values, variables, and operators that evaluates to a value (e.g., 2 + 3).
—4—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Comments
Comments are ignored by Python. They exist for human readers.
# This is a single-line comment
x = 5 # Inline comment
"""
This is a multi-line string often used
as a block comment or docstring.
"""
Python Indentation
Python uses indentation (typically 4 spaces) to define code blocks. This is NOT optional — incorrect indentation
causes an IndentationError. Unlike C/Java there are no curly braces.
if True:
print("Inside the if block") # 4 spaces
print("Still inside")
print("Outside the if block")
■ PEP 8 (Python's style guide) recommends 4 spaces per indentation level. Never mix tabs and spaces.
Running Python
Python files use the .py extension. Run from a terminal with: python [Link] or python3 [Link].
Interactive mode is started by typing python3 with no arguments.
—5—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Integer
age = 25
big = 1_000_000 # underscores allowed for readability
print(type(age)) # <class 'int'>
# Float
pi = 3.14159
scientific = 6.022e23 # Avogadro's number
print(type(pi)) # <class 'float'>
# Bool
is_student = True
passed = False
print(type(is_student)) # <class 'bool'>
print(True + True) # 2 (bool is a subtype of int!)
# String
name = 'Alice'
greeting = "Hello, World!"
multiline = """Line 1
Line 2
Line 3"""
print(type(name)) # <class 'str'>
—6—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# None
result = None
print(result is None) # True (use 'is', not ==)
# Complex
z = 2 + 3j
print([Link], [Link]) # 2.0 3.0
# Multiple assignment
a, b, c = 1, 2, 3
a = b = c = 0 # chain assignment
# Explicit — int()
print(int(3.9)) # 3 (truncates, does NOT round)
print(int("42")) # 42
print(int(True)) # 1
print(int("0b1010", 2))# 10 (binary string)
# Explicit — float()
print(float("3.14")) # 3.14
print(float(7)) # 7.0
# Explicit — str()
print(str(100)) # '100'
print(str(3.14)) # '3.14'
print(str(True)) # 'True'
—7—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Explicit — bool()
# Falsy values: 0, 0.0, '', None, [], {}, ()
print(bool(0)) # False
print(bool(42)) # True
print(bool("")) # False
print(bool("hello")) # True
String Basics
s = "Hello, Python!"
# Indexing (0-based)
print(s[0]) # H
print(s[-1]) # ! (negative = from end)
# Length
print(len(s)) # 14
—8—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 3 Loops
for · while · range · for-each · break · continue · else
Why Loops?
A loop is a control structure that repeats a block of code. Instead of writing the same statement 1000 times, a
loop iterates automatically.
Iteration
One execution of the loop body.
Iterable
Any object that can be looped over: list, string, range, dict, file, etc.
Iterator
An object that remembers its position in an iterable and produces the next value on each call to next().
for Loop
Python's for loop is a for-each loop — it iterates over each item in an iterable. There is no traditional C-style
for(int i=0; i<n; i++) in Python.
# Iterate over a list
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
range()
—9—
Comprehensive Python Guide Sections 1–18 · All Skill Levels
range() generates a sequence of integers. It is memory-efficient — it doesn't create a list, it generates numbers
on the fly.
range(stop) # 0, 1, ..., stop-1
range(start, stop) # start, start+1, ..., stop-1
range(start, stop, step) # step can be negative
while Loop
A while loop repeats as long as a condition is True. Use it when you don't know ahead of time how many
iterations are needed.
# Basic while
count = 0
while count < 5:
print(count)
count += 1 # IMPORTANT: update the condition variable
— 10 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
if i % 2 == 0:
continue
print(i, end=" ") # 1 3 5 7 9
■ The else of a loop is NOT 'if the condition was False'. It means 'loop finished without break'.
— 11 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Nested Loops
A loop inside another loop. The inner loop runs its full cycle for each iteration of the outer loop. Useful for 2-D
structures like grids and matrices.
# Multiplication table
for i in range(1, 4):
for j in range(1, 4):
print(i * j, end="\t")
print() # newline after each row
# 1 2 3
# 2 4 6
# 3 6 9
Nested Conditionals
x = 15
if x > 0:
if x % 2 == 0:
print("positive even")
else:
print("positive odd") # ← printed
else:
print("non-positive")
— 12 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
def outer():
x = "enclosing" # Enclosing scope
def inner():
x = "local" # Local scope
print(x) # local (L wins)
inner()
print(x) # enclosing (E wins inside outer)
outer()
print(x) # global
global keyword
To assign to a global variable inside a function, declare it with global. Without it, you'd create a new local
variable instead.
count = 0
def increment():
global count
count += 1
increment()
increment()
print(count) # 2
nonlocal keyword
Used in nested functions to modify a variable in the enclosing (but not global) scope.
def make_counter():
n = 0
def increment():
nonlocal n
n += 1
return n
return increment
c = make_counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
■ Avoid overusing global/nonlocal. They make code harder to reason about. Prefer passing values as arguments
and returning results.
— 13 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 5 Operations
arithmetic · comparison · logical · bitwise · math library · shorthand
Arithmetic Operators
+ Addition: 5 + 3 = 8
- Subtraction: 5 - 3 = 2
* Multiplication: 5 * 3 = 15
% Modulus (remainder): 7 % 2 = 1
** Exponentiation: 2 ** 10 = 1024
print(10 / 3) # 3.3333333333333335
print(10 // 3) # 3
print(-7 // 2) # -4 (floor toward -inf, NOT truncate!)
print(10 % 3) # 1
print(2 ** 8) # 256
Comparison Operators
x, y = 5, 10
print(x == y) # False equal to
print(x != y) # True not equal
print(x < y) # True less than
print(x > y) # False greater than
print(x <= y) # True less than or equal
print(x >= y) # False greater than or equal
Logical Operators
# and, or, not
print(True and False) # False
print(True or False) # True
print(not True) # False
— 14 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Short-circuit evaluation
# 'and' stops at first False; 'or' stops at first True
x = 0
print(x != 0 and 10/x > 1) # False (10/x never evaluated!)
# Truthy/Falsy
print(bool([])) # False (empty list)
print(bool([1])) # True
print(42 or "hi") # 42 (returns first truthy value, not bool!)
print(0 or "hi") # 'hi'
print(0 and "hi") # 0 (returns first falsy value)
Bitwise Operators
# Operate on integer bits
print(5 & 3) # 1 AND: 0101 & 0011 = 0001
print(5 | 3) # 7 OR: 0101 | 0011 = 0111
print(5 ^ 3) # 6 XOR: 0101 ^ 0011 = 0110
print(~5) # -6 NOT: flips all bits
print(5 << 1) # 10 left shift (multiply by 2)
print(5 >> 1) # 2 right shift (integer divide by 2)
print([Link]) # 3.141592653589793
print(math.e) # 2.718281828459045
print([Link](144)) # 12.0
print([Link](2, 10)) # 1024.0 (returns float)
print([Link](100, 10)) # 2.0 log base 10
print(math.log2(64)) # 6.0
print([Link](math.e)) # 1.0 natural log
print([Link](-3.2)) # -4
print([Link](-3.2)) # -3
— 15 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
— 16 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Defining Functions
Function
A named, reusable block of code that performs a specific task. Defined with def.
Parameter
A variable in the function definition (the placeholder).
Argument
The actual value passed when calling the function.
Return Value
The value the function hands back to the caller via return. Without return, Python returns None.
def greet(name): # 'name' is a parameter
return f"Hello, {name}!"
lo, hi = min_max([3,1,9,5])
print(lo, hi) # 1 9
— 17 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
print(total(1, 2, 3)) # 6
print(total(1, 2, 3, 4, 5)) # 15
# Combining them
def mixed(required, *args, **kwargs):
print(required, args, kwargs)
print(area(5)) # 25
print(area(4, 6)) # 24
# Using isinstance()
def double(x):
if isinstance(x, str):
return x * 2 # "hi" → "hihi"
return x * 2 # 5 → 10
— 18 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Docstrings
def celsius_to_fahrenheit(c):
"""
Convert Celsius to Fahrenheit.
Args:
c (float): Temperature in Celsius.
Returns:
float: Temperature in Fahrenheit.
Example:
>>> celsius_to_fahrenheit(100)
212.0
"""
return c * 9/5 + 32
■ Good functions do ONE thing, have a clear name, and are under ~20 lines. This is the Single Responsibility
Principle.
— 19 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 7 Input
input() · tokens · parsing · type conversion · validation
# More concisely:
age = int(input("Enter your age: "))
Tokens
Token
A meaningful unit of data in a string, separated by whitespace (or another delimiter). '3 hello 4.5' has three
tokens: '3', 'hello', '4.5'.
# Reading multiple tokens on one line
line = input("Enter two numbers: ") # e.g., "7 13"
tokens = [Link]() # ['7', '13']
a = int(tokens[0])
b = int(tokens[1])
print(a + b)
# Reading floats
x, y = map(float, input("Two floats: ").split())
print(x + y)
— 20 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Multi-line Input
# Reading n lines
n = int(input())
values = []
for _ in range(n):
[Link](int(input()))
print(sum(values))
# Reading a grid
rows, cols = map(int, input().split())
grid = []
for _ in range(rows):
row = list(map(int, input().split()))
[Link](row)
Input Validation
# Using a while loop + try/except to ensure valid input
while True:
try:
age = int(input("Enter your age (0-120): "))
if 0 <= age <= 120:
break
else:
print("Age must be between 0 and 120.")
except ValueError:
print("Please enter a whole number.")
■ Always validate user input before using it. Never assume the user will enter data in the correct format.
— 21 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 8 Conditionals
if · elif · else · ternary · match-case
if / elif / else
Conditionals let the program choose between paths of execution based on Boolean expressions.
score = 85
Nested Conditionals
x = 10
if x > 0:
if x < 100:
print("small positive")
else:
print("large positive")
else:
print("non-positive")
— 22 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
match command:
case "quit":
print("Quitting...")
case "help":
print("Available commands: quit, help, start")
case "start":
print("Starting...")
case _: # default (wildcard)
print(f"Unknown command: {command}")
# Check if None
value = None
if value is None:
print("no value")
if value is not None:
print("has value")
# Truthy/Falsy checks
name = ""
if not name:
— 23 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
print("Name is empty")
items = []
if items:
print("Has items")
else:
print("Empty list")
— 24 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
F-strings (f-literals)
Introduced in Python 3.6. Prefix a string with f or F and embed expressions in {}.
name = "Alice"
age = 30
pi = 3.14159
Format Specifications
Inside the braces: {value:format_spec}. Format spec syntax:
[[fill]align][sign][#][0][width][grouping][.precision][type]
x = 3.14159265
# Scientific notation
print(f"{12345.6789:.2e}") # 1.23e+04
# Integers
n = 255
print(f"{n:d}") # 255 (decimal)
print(f"{n:b}") # 11111111 (binary)
print(f"{n:o}") # 377 (octal)
print(f"{n:x}") # ff (hex lower)
print(f"{n:X}") # FF (hex upper)
print(f"{n:#x}") # 0xff (with prefix)
print(f"{n:08b}") # 11111111 (zero-padded binary)
# Strings
— 25 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
s = "hello"
print(f"{s:>10}") # ' hello' right-aligned in width 10
print(f"{s:*^10}") # '**hello***' centered with * fill
# Thousands separator
big = 1234567
print(f"{big:,}") # 1,234,567
print(f"{big:_}") # 1_234_567
[Link]() Method
# Positional
print("Hello, {}! You are {} years old.".format("Bob", 25))
# Named
print("{name} scored {score}%".format(name="Alice", score=95))
% Formatting (legacy)
# Old C-style formatting — still seen in older code
print("Hello, %s! You are %d years old." % ("Bob", 25))
print("Pi = %.4f" % 3.14159)
■ Use f-strings for new code. They are faster, more readable, and more powerful.
— 26 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 10 Random
random module · seeding · distributions · secrets
Importing random
import random
Core Functions
import random
Seeding
A seed initialises the random number generator. With the same seed you get the same sequence every time —
essential for reproducibility in testing and simulations.
[Link](42)
print([Link](1, 100)) # always 82 with seed 42
print([Link](1, 100)) # always 15
[Link](42) # reset
— 27 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Weighted Choices
# weights don't need to sum to 1
outcomes = ["win", "lose", "draw"]
weights = [1, 3, 1] # 20% win, 60% lose, 20% draw
print([Link](outcomes, weights=weights, k=10))
Gaussian Distribution
# Gaussian (normal) distribution: mu=mean, sigma=std dev
heights = [[Link](170, 10) for _ in range(5)]
print([f"{h:.1f}" for h in heights])
— 28 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Boolean Zen
Avoid comparing booleans to True/False — the boolean IS the condition.
is_valid = True
# BAD — redundant
if is_valid == True:
pass
# GOOD
if is_valid:
pass
# BAD
if found == False:
pass
# GOOD
if not found:
pass
# GOOD
def is_even(n):
return n % 2 == 0
Assertions
An assertion is a claim that something must be true at a specific point in the program. Used for debugging and
testing preconditions/postconditions.
— 29 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Checking postconditions
def sort_list(lst):
result = sorted(lst)
assert result == sorted(result), "Result is not sorted!"
return result
■ Assertions can be disabled with python -O flag. Do NOT use them for user input validation — use if/raise instead.
Fencepost Problem
The fencepost problem (also called off-by-one error) arises when you confuse the number of posts vs the
number of gaps between posts.
# WRONG: prints comma after last element
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit, end=", ")
# apple, banana, cherry, ← extra comma!
# Fencepost in range:
# A fence 10 meters long with posts every 2 meters
# has 6 posts but only 5 gaps
fence_length = 10
spacing = 2
posts = fence_length // spacing + 1 # 6, NOT 5
gaps = fence_length // spacing # 5
Lookahead
A lookahead reads or inspects the NEXT element before consuming the current one. Useful for processing
sequences that require context from adjacent items.
# Detect consecutive duplicates
nums = [1, 2, 2, 3, 4, 4, 4, 5]
for i in range(len(nums) - 1): # -1 = lookahead safety
if nums[i] == nums[i+1]:
print(f"Duplicate at index {i}: {nums[i]}")
— 30 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
DeMorgan's Laws
DeMorgan's Laws allow you to rewrite complex logical expressions. Invaluable for simplifying conditions.
x, y = 3, 8
# Original
if not (x > 5 and y < 10):
print("DeMorgan 1")
— 31 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Line-Based Reading
# Method 1: readline() — one line at a time
with open("[Link]") as f:
line = [Link]()
while line:
print([Link]()) # strip() removes trailing \n
line = [Link]()
— 32 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Token-Based Reading
# Read file word by word
with open("[Link]") as f:
for line in f:
tokens = [Link]()
for token in tokens:
print(token)
Writing to Files
# Write mode — creates or overwrites
with open("[Link]", "w") as f:
[Link]("Hello\n")
[Link]("World\n")
print("From print", file=f) # redirect print to file
# Append mode
with open("[Link]", "a") as f:
[Link]("New log entry\n")
CSV Files
import csv
# Reading CSV
with open("[Link]", "r", newline="") as f:
reader = [Link](f)
header = next(reader) # skip header row
for row in reader:
print(row) # each row is a list
# Writing CSV
data = [
["Alice", 95, "A"],
["Bob", 82, "B"],
]
with open("[Link]", "w", newline="") as f:
writer = [Link](f)
[Link](["Name", "Score", "Grade"])
— 33 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
[Link](data)
■ Always handle FileNotFoundError when opening files that may not exist: try: ... except FileNotFoundError:
print('File not found')
— 34 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Arrays in Python
Python does not have a built-in array type in the traditional sense. Lists serve as dynamic arrays. For fixed-type
numeric arrays, use the array module or NumPy. This section covers list-as-array patterns you'll see in CS
coursework.
Array
A contiguous collection of elements accessible by integer index. O(1) access by index.
Dynamic Array
An array that can grow; Python lists are dynamic arrays. Appending is amortised O(1).
List Properties
nums = [10, 20, 30, 40, 50]
# Length
print(len(nums)) # 5
# Indexing — 0-based
print(nums[0]) # 10 first element
print(nums[-1]) # 50 last element
print(nums[-2]) # 40
# Mutation
nums[2] = 99
print(nums) # [10, 20, 99, 40, 50]
# Common operations
[Link](60) # add to end
[Link](0, 5) # insert at index
[Link](99) # remove first occurrence of value
popped = [Link]() # remove & return last
popped2 = [Link](1) # remove & return at index
[Link]() # in-place sort
[Link]() # in-place reverse
print([Link](40)) # index of first 40
print([Link](20)) # occurrences of 20
— 35 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Value Semantics
Primitives (int, float, bool, str, tuple) behave as if copied on assignment. Assigning to a new variable does
not affect the original.
Reference Semantics
Lists (and other mutable objects) are passed by reference — multiple variables can point to the SAME list
object.
# Value semantics with ints
a = 5
b = a # b gets a COPY of the value
b = 10
print(a) # 5 — unchanged!
nums = [1, 2, 3]
zero_first(nums)
print(nums) # [0, 2, 3]
— 36 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# WARNING: Do NOT use [[0]*cols]*rows — all rows share the same list!
# Traverse
for row in matrix:
for val in row:
print(val, end=" ")
print()
# With condition
evens = [x for x in range(20) if x % 2 == 0]
# map/filter equivalents
squares2 = list(map(lambda x: x**2, range(10)))
odds = list(filter(lambda x: x%2 != 0, range(10)))
— 37 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
— 38 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Unpacking
a, b, *rest = primes
print(a, b, rest) # 2 3 [5, 7, 11, 13, 17, 19]
Tuples
Tuples are ordered, IMMUTABLE sequences. Once created, they cannot be changed. They are faster than lists
and hashable (can be used as dictionary keys or set elements).
# Tuple creation
point = (3, 4)
single = (42,) # trailing comma REQUIRED for single-element tuple
empty = ()
# Unpacking
x, y = point
print(x, y) # 3 4
— 39 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Dictionaries
Dictionaries map unique keys to values. Implemented as hash tables — O(1) average lookups, insertions, and
deletions.
# Creation
student = {"name": "Alice", "age": 20, "gpa": 3.8}
empty = {}
also = dict(name="Bob", age=22)
# Access
print(student["name"]) # Alice
print([Link]("major")) # None (no KeyError)
print([Link]("major", "Undeclared")) # Undeclared
# Mutation
student["age"] = 21
student["major"] = "CS"
del student["gpa"]
# Iteration
for key in student:
print(key, student[key])
print(list([Link]()))
print(list([Link]()))
Dictionary Comprehensions
— 40 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Filter
passing = {name: score
for name, score in {"Alice":95,"Bob":55,"Carol":78}.items()
if score >= 60}
Sets
Sets are unordered collections of unique elements. Great for membership tests and set operations.
# Creation
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
s = set() # empty set (NOT {} which is an empty dict!)
# Membership — O(1)
print(3 in a) # True
# Set operations
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) # symmetric diff: {1,2,5,6}
# Set comprehension
evens = {x for x in range(20) if x % 2 == 0}
— 41 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Object-Oriented Programming
Object
A bundle of data (attributes) and behaviour (methods).
Class
A blueprint/template for creating objects.
Instance
A concrete object created from a class.
Attribute
A variable belonging to an object (state).
Method
A function belonging to a class (behaviour).
self
The first parameter of every instance method; refers to the instance itself.
Defining a Class
class Dog:
# Class variable — shared by ALL instances
species = "Canis lupus familiaris"
# Instance method
def bark(self):
return f"{[Link]} says: Woof!"
def birthday(self):
[Link] += 1
# String representation
def __str__(self):
return f"Dog({[Link]}, {[Link]}yo, {[Link]})"
def __repr__(self):
return f"Dog(name={[Link]!r}, age={[Link]}, breed={[Link]!r})"
— 42 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Creating instances
d1 = Dog("Rex", 3, "German Shepherd")
d2 = Dog("Fluffy", 1, "Poodle")
Static vs Instance
Instance variable
Defined with self.x. Each instance has its own copy.
Class variable
Defined at class level (no self). Shared across all instances.
Instance method
Takes self. Operates on instance data.
Class method
Decorated with @classmethod. Takes cls. Operates on class data.
Static method
Decorated with @staticmethod. No self or cls. Utility function.
class Counter:
total_created = 0 # class variable
@classmethod
def get_total(cls): # class method
return cls.total_created
@staticmethod
def description(): # static method
return "A simple counter"
c1 = Counter()
c2 = Counter(10)
[Link]()
print([Link]) # 1
— 43 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
print([Link]) # 10
print(Counter.get_total()) # 2
print([Link]())
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # (4, 6)
print(v1 * 3) # (3, 6)
print(v1 == v2) # False
— 44 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
1. Encapsulation
Encapsulation
Bundling data and the methods that operate on that data within one unit (class), and restricting direct
access to internal state. Protects invariants.
class BankAccount:
def __init__(self, owner, balance=0):
[Link] = owner
self._balance = balance # convention: _ = 'private'
# Getter
@property
def balance(self):
return self._balance
2. Inheritance
Inheritance
A class (child/subclass) derives attributes and methods from another class (parent/superclass). Enables
code reuse and is-a relationships.
— 45 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
class Animal:
def __init__(self, name, age):
[Link] = name
[Link] = age
def eat(self):
print(f"{[Link]} is eating.")
def speak(self):
raise NotImplementedError("Subclass must implement speak()")
def __str__(self):
return f"{type(self).__name__}({[Link]}, {[Link]}yo)"
class Cat(Animal):
def speak(self):
return "Meow!"
d = Dog("Rex", 3, "Lab")
c = Cat("Whiskers", 5)
3. Polymorphism
Polymorphism
The ability of different objects to respond to the same message (method call) in different ways. 'Many
forms'. Python achieves this through method overriding and duck typing.
# All Animals can speak(), but each does so differently
animals = [Dog("Rex",3,"Lab"), Cat("Luna",2), Dog("Buddy",1,"Poodle")]
— 46 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Woof!
# Neither inherits from Animal, but we can use them the same way:
things = [Duck(), Robot()]
for t in things:
print([Link]()) # Quack! Beep boop
4. Abstraction
Abstraction
Hiding complex implementation details and exposing only the essential interface. Users know WHAT
something does, not HOW it does it. Achieved via abstract base classes and clean interfaces.
from abc import ABC, abstractmethod
@abstractmethod
def perimeter(self):
pass
class Circle(Shape):
def __init__(self, radius):
[Link] = radius
def area(self):
import math
return [Link] * [Link] ** 2
def perimeter(self):
import math
return 2 * [Link] * [Link]
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
def perimeter(self):
— 47 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
— 48 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
# Sorting objects
students = [("Alice",95), ("Bob",82), ("Carol",91)]
[Link](key=lambda s: s[1], reverse=True)
print(students) # [('Alice',95),('Carol',91),('Bob',82)]
— 49 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
nums = [4, 2, 7, 1, 9, 3]
print(linear_search(nums, 7)) # 2
print(linear_search(nums, 5)) # -1
— 50 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
— 51 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
Section 18 Recursion
base case · recursive case · call stack · memoization · classic problems
What is Recursion?
Recursion is when a function calls itself to solve a smaller version of the same problem. Every recursive
solution must have:
• Base case — the simplest input that can be solved directly (no further recursion).
• Recursive case — break the problem into a smaller sub-problem and call self.
• Progress toward the base case — each call must bring the problem closer to the base case.
Call Stack
Each function call pushes a frame onto the call stack. Recursive calls stack up until the base case is hit,
then they 'unwind'. Python's default stack limit is ~1000 frames ([Link]() can increase it).
print(factorial(5)) # 120
print(factorial(0)) # 1
Fibonacci
# Naive recursion — O(2^n), very slow
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
# Memoized — O(n)
from functools import lru_cache
— 52 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
@lru_cache(maxsize=None)
def fib_memo(n):
if n <= 1:
return n
return fib_memo(n-1) + fib_memo(n-2)
Sum of a List
def recursive_sum(lst):
if len(lst) == 0:
return 0
return lst[0] + recursive_sum(lst[1:])
print(recursive_sum([1,2,3,4,5])) # 15
Power Function
def power(base, exp):
if exp == 0:
return 1
return base * power(base, exp - 1)
— 53 —
Comprehensive Python Guide Sections 1–18 · All Skill Levels
print(binary_search_rec(nums, 7, 0, len(nums)-1)) # 3
Tower of Hanoi
def hanoi(n, source, destination, auxiliary):
"""Move n disks from source to destination using auxiliary."""
if n == 1:
print(f"Move disk 1 from {source} to {destination}")
return
hanoi(n-1, source, auxiliary, destination)
print(f"Move disk {n} from {source} to {destination}")
hanoi(n-1, auxiliary, destination, source)
Recursion vs Iteration
Recursion often mirrors the mathematical definition; iteration is more
Readability explicit.
Deep recursion can hit Python's ~1000 frame limit; iteration does
Stack limit not.
End of Guide
You have covered all 18 sections of this Comprehensive Python Programming Guide.
Happy coding! ■
— 54 —