0% found this document useful (0 votes)
5 views48 pages

Python Learning Guide v2

The document is a comprehensive learning guide for Python, covering essential topics such as installation, data types, control flow, functions, and data structures across 13 chapters. It includes practical examples, real projects, and deep dives into advanced concepts, making it suitable for beginners to confident coders. The guide emphasizes Python's versatility and popularity in various fields like web development, data science, and AI.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views48 pages

Python Learning Guide v2

The document is a comprehensive learning guide for Python, covering essential topics such as installation, data types, control flow, functions, and data structures across 13 chapters. It includes practical examples, real projects, and deep dives into advanced concepts, making it suitable for beginners to confident coders. The guide emphasizes Python's versatility and popularity in various fields like web development, data science, and AI.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Python
Complete Learning Guide — Edition 2

Basic → Confident Coder · Real Projects · Deep Dives · Extra Knowledge

13 Chapters 80+ Examples Real Projects Deep Dives Extra Modules


Table of Contents
Getting Started
01
Install, first program, how Python runs

Variables & Data Types


02
Numbers, strings, booleans, type conversion

Control Flow
03
if/elif/else, for, while, break, continue

Functions
04
Def, args, defaults, *args/**kwargs, lambda

Data Structures
05
Lists, tuples, sets, dicts + comprehensions

Strings In Depth
06
Slicing, methods, f-strings, regex intro

File Handling
07
Read/write/CSV/JSON + context managers

Error Handling
08
try/except/finally, custom exceptions

Object-Oriented Python
09
Classes, inheritance, dunder methods

Modules & the Standard Library


10
os, math, random, datetime, collections

Advanced Functions
11
Decorators, generators, iterators, closures

List/Dict Comprehensions+
12
Comprehensions, zip, map, filter, walrus

Practical Projects
13
Number game, password gen, data analyser, OOP bank
CHAPTER 01

Getting Started
Install Python & write your first real programs

■ Quick Summary

■ Python is free, cross-platform, and beginner-friendly

■ Download from [Link] — tick 'Add to PATH' on Windows

■ Run scripts with: python [Link]

■ print() displays output; input() reads keyboard input

■ Indentation (4 spaces) is mandatory — it defines code blocks

What is Python & Why Learn It?


Python is a high-level, interpreted language created by Guido van Rossum in 1991. It is used in web
development (Django, Flask), data science (pandas, NumPy), AI & machine learning (TensorFlow,
PyTorch), automation, game dev, and more. Its clean syntax makes it the world's most popular first
language.

■ Key Concept: Python ranks #1 on the TIOBE index and is the top language for data science and AI.

Installing & Running Python


1. Go to [Link]/downloads and grab the latest version.
2. On Windows: check Add Python to PATH during setup.
3. Open a terminal and type python --version to confirm.
4. Write code in any editor (VS Code, PyCharm, IDLE, Notepad).

Your First Programs


■ [Link] — classic first program

print("Hello, World!")
print("Python is awesome!")
Hello, World!
Python is awesome!
■ greet_user.py — interactive input

name = input("Enter your name: ")


age = int(input("Enter your age: "))
print(f"Hi {name}! In 10 years you will be {age + 10}.")
Enter your name: Alice
Enter your age: 22
Hi Alice! In 10 years you will be 32.

■ math_intro.py — Python as a calculator

print(2 + 3) # 5
print(10 / 3) # 3.333...
print(10 // 3) # 3 (floor division)
print(10 % 3) # 1 (remainder)
print(2 ** 8) # 256 (power)
print(abs(-42)) # 42
print(round(3.7)) # 4
5
3.3333333333333335
3
1
256
42
4

Comments & Code Style


■ [Link]

# Single-line comment — Python ignores this

"""
Multi-line string used as a docstring / block comment.
Great for describing what a function does.
"""

x = 10 # inline comment — keep these brief

# PEP 8 style: use snake_case for variables


user_name = "Alice"
MAX_SCORE = 100 # UPPER_CASE for constants

■ Tip: Run python -m py_compile [Link] to check for syntax errors before running.
CHAPTER 02

Variables & Data Types


Store, label and transform every kind of data

■ Quick Summary

■ Variables are labels pointing to values — no type declaration needed

■ Core types: int, float, str, bool, NoneType

■ Use type() to inspect a variable's type

■ Convert between types with int(), float(), str(), bool()

■ Multiple assignment: a, b, c = 1, 2, 3

Variables — Deep Dive


Python uses dynamic typing: you never declare a type — Python infers it. Variables are just names
that point to objects in memory. The same name can point to different types at different times.

■ variables_deep.py

score = 0 # int
score = score + 10 # still int
score = "ten" # now a string — Python allows this!

# Multiple assignment on one line


x, y, z = 10, 20, 30
a = b = c = 0 # all point to the same 0

# Swap without a temp variable (Python magic!)


x, y = y, x
print(x, y) # 20 10
20 10

Numbers
■ [Link]

i = 1_000_000 # underscores for readability


f = 3.14159
c = 2 + 3j # complex number

print(type(i)) # <class "int">


print(type(f)) # <class "float">
print(type(c)) # <class "complex">

# Useful built-ins
print(max(3, 7, 1)) # 7
print(min(3, 7, 1)) # 1
print(sum([10, 20, 30])) # 60
print(divmod(17, 5)) # (3, 2) → quotient & remainder
<class 'int'>
<class 'float'>
<class 'complex'>
7
1
60
(3, 2)

Booleans & None


■ [Link]

is_raining = True
has_umbrella = False

# Booleans are just ints (True=1, False=0)


print(True + True) # 2
print(True * 10) # 10

# Falsy values — all evaluate to False in a condition


falsy = [0, 0.0, "", [], {}, None, False]
for val in falsy:
print(f"{repr(val):10} → {bool(val)}")

# None means "no value"


result = None
print(result is None) # True (use "is", not "==")
2
10
0 → False
0.0 → False
'' → False
...
Type Conversion — Real Example
■ type_conversion.py — temperature converter

celsius_str = input("Enter temperature in Celsius: ")


celsius = float(celsius_str)
fahrenheit = celsius * 9/5 + 32
kelvin = celsius + 273.15

print(f"{celsius}°C = {fahrenheit:.1f}°F = {kelvin:.2f}K")


Enter temperature in Celsius: 100
100.0°C = 212.0°F = 373.15K

■■ Warning: Always convert input() strings to int/float before doing arithmetic — input always returns a
string.
CHAPTER 03

Control Flow
Decisions, loops, and branching logic

■ Quick Summary

■ if/elif/else lets your program make decisions

■ for loops iterate over sequences; while loops run until a condition is False

■ break exits a loop immediately; continue skips to the next iteration

■ range(start, stop, step) generates number sequences

■ else on a loop runs only if the loop completed without break

if / elif / else
■ bmi_calculator.py — real-world example

weight = float(input("Weight (kg): "))


height = float(input("Height (m): "))
bmi = weight / (height ** 2)

if bmi < 18.5:


category = "Underweight"
elif bmi < 25.0:
category = "Normal weight"
elif bmi < 30.0:
category = "Overweight"
else:
category = "Obese"

print(f"BMI: {bmi:.1f} — {category}")


Weight (kg): 70
Height (m): 1.75
BMI: 22.9 — Normal weight

Ternary (One-Line) if
■ [Link]

age = 20
status = "adult" if age >= 18 else "minor"
print(status) # adult

# Clamp a number between 0 and 100


score = 115
score = max(0, min(score, 100))
print(score) # 100
adult
100

for Loops — Deep Dive


■ for_loops.py

# enumerate gives index AND value


fruits = ["apple", "banana", "cherry"]
for i, fruit in enumerate(fruits, start=1):
print(f"{i}. {fruit}")

# zip pairs two lists together


names = ["Alice", "Bob", "Carol"]
scores = [95, 87, 92]
for name, score in zip(names, scores):
print(f"{name}: {score}/100")

# range with step


print(list(range(0, 20, 5))) # [0, 5, 10, 15]
1. apple
2. banana
3. cherry
Alice: 95/100
Bob: 87/100
Carol: 92/100
[0, 5, 10, 15]

while Loop — Guess the Number


■ while_guess.py — mini game

import random
secret = [Link](1, 10)
attempts = 0

while True:
guess = int(input("Guess (1-10): "))
attempts += 1
if guess < secret:
print("Too low!")
elif guess > secret:
print("Too high!")
else:
print(f"Correct in {attempts} attempts!")
break
Guess (1-10): 5
Too high!
Guess (1-10): 3
Too low!
Guess (1-10): 4
Correct in 3 attempts!

Loop Patterns
■ loop_patterns.py

# Find first even number — loop else


numbers = [3, 7, 11, 4, 9]
for n in numbers:
if n % 2 == 0:
print(f"First even: {n}")
break
else:
print("No even numbers found")

# Skip multiples of 3, print rest


for i in range(1, 11):
if i % 3 == 0:
continue
print(i, end=" ")
First even: 4
1 2 4 5 7 8 10
CHAPTER 04

Functions
Reusable, organised, testable blocks of code

■ Quick Summary

■ def name(params): body — defines a function

■ return sends a value back to the caller

■ Default parameters make arguments optional

■ *args collects extra positional args as a tuple

■ **kwargs collects extra keyword args as a dict

■ lambda: anonymous one-liner functions

■ Scope: variables inside functions are local

Defining Functions — Deep Dive


■ functions_deep.py

def greet(name, greeting="Hello"):


"""Return a personalised greeting string."""
return f"{greeting}, {name}!"

print(greet("Alice")) # Hello, Alice!


print(greet("Bob", "Good morning"))# Good morning, Bob!
print(greet(greeting="Hi","Carol"))# SyntaxError: positional after keyword

# Multiple return values (returns a tuple)


def min_max(numbers):
return min(numbers), max(numbers)

lo, hi = min_max([5, 2, 8, 1, 9])


print(f"Min={lo}, Max={hi}") # Min=1, Max=9
Hello, Alice!
Good morning, Bob!
Min=1, Max=9

*args and **kwargs — Real Example


■ args_kwargs.py — flexible logger

def log(*messages, level="INFO", sep=" | "):


prefix = f"[{level}]"
print(prefix, [Link](str(m) for m in messages))

log("Server started") # [INFO] Server started


log("404", "Not found", level="ERROR") # [ERROR] 404 | Not found
log("a","b","c", level="DEBUG", sep=" - ")# [DEBUG] a - b - c

def make_profile(**info):
for k, v in [Link]():
print(f" {k:12}: {v}")

make_profile(name="Alice", age=25, role="Developer")


[INFO] Server started
[ERROR] 404 | Not found
[DEBUG] a - b - c
name : Alice
age : 25
role : Developer

Lambda Functions
■ [Link]

# Sort students by grade (descending)


students = [
{"name": "Alice", "grade": 88},
{"name": "Bob", "grade": 95},
{"name": "Carol", "grade": 72},
]
[Link](key=lambda s: s["grade"], reverse=True)
for s in students:
print(f" {s['name']:8} {s['grade']}")

# Lambda with map and filter


nums = [1, 2, 3, 4, 5, 6]
doubled = list(map(lambda x: x*2, nums))
evens = list(filter(lambda x: x%2==0, nums))
print(doubled) # [2, 4, 6, 8, 10, 12]
print(evens) # [2, 4, 6]
Bob 95
Alice 88
Carol 72
[2, 4, 6, 8, 10, 12]
[2, 4, 6]
Scope — LEGB Rule
■ [Link]

x = "global"

def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # local
inner()
print(x) # enclosing

outer()
print(x) # global

# Use global keyword to modify a global


counter = 0
def increment():
global counter
counter += 1

increment(); increment()
print(counter) # 2
local
enclosing
global
2

■■ Warning: Avoid using global — prefer returning values from functions and reassigning at the call
site.
CHAPTER 05

Data Structures
Lists, Tuples, Sets & Dictionaries

■ Quick Summary

■ List [ ] — ordered, mutable, allows duplicates

■ Tuple ( ) — ordered, immutable, slightly faster than list

■ Set { } — unordered, mutable, NO duplicates

■ Dict {k:v} — key→value mapping, ordered (Python 3.7+)

■ Comprehensions create collections in one readable line

Lists — Full Guide


■ lists_full.py

numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# Slicing
print(numbers[2:5]) # [4, 1, 5]
print(numbers[::-1]) # reversed

# Methods
[Link]() # in-place sort
[Link](7)
[Link](0, 0)
[Link](1) # removes first 1

# List as a stack (LIFO)


stack = []
[Link]("page1")
[Link]("page2")
print([Link]()) # page2

# Flatten nested list


nested = [[1,2],[3,4],[5,6]]
flat = [x for row in nested for x in row]
print(flat) # [1, 2, 3, 4, 5, 6]
[4, 1, 5]
[6, 2, 9, 5, 1, 4, 1, 3]
page2
[1, 2, 3, 4, 5, 6]

Dictionaries — Deep Dive


■ dicts_deep.py

# Word frequency counter


text = "the cat sat on the mat the cat"
freq = {}
for word in [Link]():
freq[word] = [Link](word, 0) + 1

for word, count in sorted([Link](), key=lambda x: -x[1]):


print(f" {word:6}: {'*' * count} ({count})")

# Dict comprehension
squares = {x: x**2 for x in range(1, 6)}
print(squares)
the : *** (3)
cat : ** (2)
sat : * (1)
on : * (1)
mat : * (1)
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Sets — Practical Uses


■ [Link]

# Remove duplicates while preserving concepts


emails = ["a@[Link]","b@[Link]","a@[Link]","c@[Link]"]
unique = list(set(emails))
print(f"{len(emails)} emails → {len(unique)} unique")

# Set operations
python_devs = {"Alice","Bob","Carol"}
js_devs = {"Bob","Dave","Carol"}

print(python_devs & js_devs) # intersection (both)


print(python_devs | js_devs) # union (all)
print(python_devs - js_devs) # difference (python only)
3 emails → 3 unique
{'Bob', 'Carol'}
{'Alice', 'Bob', 'Carol', 'Dave'}
{'Alice'}

Tuples & Unpacking


■ [Link]

# RGB colour as a tuple


RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

r, g, b = RED
print(f"Red channel: {r}") # 255

# Named tuple — like a lightweight class


from collections import namedtuple
Point = namedtuple("Point", ["x","y"])
p = Point(3, 4)
distance = (p.x**2 + p.y**2) ** 0.5
print(f"Distance from origin: {distance}") # 5.0
Red channel: 255
Distance from origin: 5.0
CHAPTER 06

Strings In Depth
Slicing, methods, formatting & regex intro

■ Quick Summary

■ Strings are immutable sequences of characters

■ Slicing: s[start:stop:step] — negative indices count from end

■ Key methods: strip, split, join, replace, find, count, upper, lower

■ f-strings support format specs: {value:.2f}, {value:>10}, {value:,}

■ re module: search, match, findall, sub for pattern matching

Slicing Mastery
■ [Link]

s = "Hello, Python World!"


# 0123456789...
print(s[7:13]) # Python
print(s[-6:]) # World!
print(s[::2]) # Hlo yhnWrd
print(s[::-1]) # !dlroW nohtyP ,olleH

# Check palindrome
def is_palindrome(word):
w = [Link]().replace(" ","")
return w == w[::-1]

print(is_palindrome("racecar")) # True
print(is_palindrome("hello")) # False
print(is_palindrome("A man a plan a canal Panama")) # True
Python
World!
Hlo yhnWrd
!dlroW nohtyP ,olleH
True
False
True

String Methods — Practical


■ str_methods.py — data cleaning

# Simulate cleaning messy CSV data


raw = [" Alice ", "BOB", "carol smith", "DAVE jones"]
cleaned = [[Link]().title() for name in raw]
print(cleaned)

# Split and rejoin


csv_line = "Alice,28,London,Developer"
fields = csv_line.split(",")
print(fields[0], "works as a", fields[3])

# Useful checks
print("abc123".isalnum()) # True
print("12345".isdigit()) # True
print("hello".startswith("he")) # True
print(",".join(["a","b","c"])) # a,b,c
['Alice', 'Bob', 'Carol Smith', 'Dave Jones']
Alice works as a Developer
True
True
True
a,b,c

Advanced f-String Formatting


■ [Link]

price = 12345.678
ratio = 0.8756
name = "Alice"

print(f"Price: ${price:>12,.2f}") # right-aligned, comma


print(f"Ratio: {ratio:.1%}") # percentage
print(f"Name: {name:*^20}") # centred, padded with *
print(f"Hex: {255:#010x}") # hex with 0x prefix
print(f"Binary: {42:08b}") # 8-bit binary
Price: $ 12,345.68
Ratio: 87.6%
Name: *******Alice*******
Hex: 0x000000ff
Binary: 00101010

Regex — Intro
■ regex_intro.py

import re

# Validate an email address


pattern = r"^[\w.+-]+@[\w-]+\.[a-z]{2,}$"
emails = ["user@[Link]", "bad@", "ok@[Link]"]
for e in emails:
status = "valid" if [Link](pattern, e) else "invalid"
print(f" {e:25} → {status}")

# Extract all numbers from a string


text = "Order 42 items at $3.99 each, total $167.58"
numbers = [Link](r"\d+\.?\d*", text)
print("Numbers found:", numbers)
user@[Link] → valid
bad@ → invalid
ok@[Link] → valid
Numbers found: ['42', '3.99', '167.58']
CHAPTER 07

File Handling
Read, write, CSV, JSON & context managers

■ Quick Summary

■ Always use 'with open(...)' — auto-closes the file safely

■ Modes: 'r' read, 'w' write (overwrites), 'a' append, 'rb' binary read

■ csv module handles comma-separated files cleanly

■ json module reads/writes JSON with loads/dumps

■ os and pathlib help manage paths, dirs, and file existence

Reading & Writing Text Files


■ text_files.py

# Write a file
lines = ["Alice,25,Engineer","Bob,30,Designer","Carol,28,Manager"]
with open("[Link]", "w") as f:
for line in lines:
[Link](line + "\n")

# Read it back and process


with open("[Link]", "r") as f:
for line in f:
name, age, role = [Link]().split(",")
print(f"{name:8} (age {age}) — {role}")
Alice (age 25) — Engineer
Bob (age 30) — Designer
Carol (age 28) — Manager

JSON Files — Config & Data


■ json_files.py

import json

# Save settings to JSON


settings = {
"theme": "dark",
"volume": 75,
"hotkeys": ["Ctrl+S","Ctrl+Z","Ctrl+Y"]
}
with open("[Link]", "w") as f:
[Link](settings, f, indent=2)

# Load it back
with open("[Link]", "r") as f:
loaded = [Link](f)

print(loaded["theme"]) # dark
print(loaded["hotkeys"]) # ["Ctrl+S", ...]
dark
["Ctrl+S", "Ctrl+Z", "Ctrl+Y"]

CSV — Student Grade Report


■ csv_grades.py

import csv

data = [
["Name","Math","Science","English"],
["Alice",92,88,95],["Bob",78,85,80],["Carol",90,92,87]
]

with open("[Link]", "w", newline="") as f:


[Link](f).writerows(data)

with open("[Link]") as f:
reader = [Link](f)
for row in reader:
avg = (int(row["Math"])+int(row["Science"])+int(row["English"]))/3
print(f"{row['Name']:8} avg: {avg:.1f}")
Alice avg: 91.7
Bob avg: 81.0
Carol avg: 89.7

File Existence & Path Management


■ file_paths.py

import os
from pathlib import Path

p = Path("data/reports")
[Link](parents=True, exist_ok=True) # create dirs

report = p / "[Link]" # build path safely


report.write_text("Report content here")

print([Link]()) # True
print([Link]) # summary
print([Link]) # .txt
print([Link]) # data/reports
True
summary
.txt
data/reports
CHAPTER 08

Error Handling
Write robust, crash-proof programs

■ Quick Summary

■ try: put risky code here; except: handle the error

■ Catch specific exceptions — avoid bare 'except:'

■ finally: always runs (cleanup, close connections, etc.)

■ raise: throw your own exceptions intentionally

■ Custom exception classes make error types descriptive

try / except / finally — Deep Dive


■ error_handling.py — safe division utility

def safe_divide(a, b):


try:
result = a / b
except TypeError as e:
return f"Type error: {e}"
except ZeroDivisionError:
return "Cannot divide by zero"
else:
return round(result, 4) # runs only if NO exception
finally:
print(f"Attempted: {a} / {b}") # ALWAYS runs

print(safe_divide(10, 3))
print(safe_divide(10, 0))
print(safe_divide("x", 2))
Attempted: 10 / 3
3.3333
Attempted: 10 / 0
Cannot divide by zero
Attempted: x / 2
Type error: unsupported operand...

Custom Exceptions — Bank Account


■ custom_exceptions.py

class BankError(Exception): pass

class InsufficientFunds(BankError):
def __init__(self, balance, amount):
super().__init__(f"Need ${amount:.2f}, only ${balance:.2f} available")
[Link] = amount - balance

class InvalidAmount(BankError):
def __init__(self, amount):
super().__init__(f"Amount must be positive, got: {amount}")

def withdraw(balance, amount):


if amount <= 0: raise InvalidAmount(amount)
if amount > balance: raise InsufficientFunds(balance, amount)
return balance - amount

for amt in [50, 200, -10]:


try:
new_bal = withdraw(100, amt)
print(f"Withdrew ${amt}. Balance: ${new_bal}")
except BankError as e:
print(f"Error: {e}")
Withdrew $50. Balance: $50
Error: Need $200.00, only $100.00 available
Error: Amount must be positive, got: -10

Input Validation Loop


■ validated_input.py

def get_int(prompt, min_val=None, max_val=None):


while True:
try:
val = int(input(prompt))
if min_val is not None and val < min_val:
raise ValueError(f"Must be >= {min_val}")
if max_val is not None and val > max_val:
raise ValueError(f"Must be <= {max_val}")
return val
except ValueError as e:
print(f" Invalid: {e}. Try again.")

age = get_int("Enter age (1-120): ", 1, 120)


print(f"Your age: {age}")
Enter age (1-120): abc
Invalid: invalid literal... Try again.
Enter age (1-120): -5
Invalid: Must be >= 1. Try again.
Enter age (1-120): 25
Your age: 25
CHAPTER 09

Object-Oriented Python
Classes, inheritance & dunder methods

■ Quick Summary

■ class defines a blueprint; objects are instances of a class

■ __init__ is the constructor — runs when you create an object

■ self refers to the current instance

■ Inheritance: class Child(Parent) — reuse and extend

■ Dunder methods (__str__, __len__, __add__) customise Python operators

■ @property turns a method into a readable attribute

Classes — Complete Example


■ classes_full.py — Student class

class Student:
school = "Python Academy" # class attribute (shared)

def __init__(self, name, grades):


[Link] = name
[Link] = grades

@property
def average(self):
return sum([Link]) / len([Link])

@property
def grade_letter(self):
avg = [Link]
return "A" if avg>=90 else "B" if avg>=80 else "C" if avg>=70 else "F"

def __str__(self):
return f"{[Link]} | avg: {[Link]:.1f} | {self.grade_letter}"

def __repr__(self):
return f"Student({[Link]!r}, {[Link]})"

alice = Student("Alice", [92, 88, 95, 90])


bob = Student("Bob", [72, 68, 75, 80])

print(alice) # uses __str__


print([Link]) # property — no ()
print([Link])
Alice | avg: 91.2 | A
91.25
Python Academy

Inheritance — Shape Hierarchy


■ [Link]

import math

class Shape:
def area(self): raise NotImplementedError
def perimeter(self): raise NotImplementedError
def describe(self):
print(f"{type(self).__name__}: area={[Link]():.2f}, "
f"perimeter={[Link]():.2f}")

class Circle(Shape):
def __init__(self, r): self.r = r
def area(self): return [Link] * self.r**2
def perimeter(self): return 2 * [Link] * self.r

class Rectangle(Shape):
def __init__(self, w, h): self.w=w; self.h=h
def area(self): return self.w * self.h
def perimeter(self): return 2*(self.w+self.h)

shapes = [Circle(5), Rectangle(4, 6)]


for s in shapes:
[Link]()
Circle: area=78.54, perimeter=31.42
Rectangle: area=24.00, perimeter=20.00

Dunder Methods — Vector Class


■ [Link]

class Vector:
def __init__(self, x, y):
self.x = x; self.y = y
def __add__(self, other):
return Vector(self.x+other.x, self.y+other.y)
def __mul__(self, scalar):
return Vector(self.x*scalar, self.y*scalar)
def __abs__(self):
return (self.x**2+self.y**2)**0.5
def __str__(self):
return f"Vector({self.x}, {self.y})"

v1 = Vector(2, 3)
v2 = Vector(1, 4)
print(v1 + v2) # Vector(3, 7)
print(v1 * 3) # Vector(6, 9)
print(abs(v1)) # 3.605...
Vector(3, 7)
Vector(6, 9)
3.605551275
CHAPTER 10

Modules & the Standard Library


os, math, random, datetime, collections

■ Quick Summary

■ import module or from module import name

■ math: sqrt, ceil, floor, pi, factorial, log, trig functions

■ random: randint, choice, shuffle, sample, random

■ datetime: today, now, timedelta, strftime

■ os/pathlib: file/directory operations

■ collections: Counter, defaultdict, deque, namedtuple

math Module
■ math_module.py

import math

print([Link]) # 3.14159...
print(math.e) # 2.71828...
print([Link](144)) # 12.0
print([Link](10)) # 3628800
print([Link](1000, 10)) # 3.0
print([Link](4.2)) # 5
print([Link](4.9)) # 4

# Hypotenuse of a right triangle


print([Link](3, 4)) # 5.0
3.141592653589793
2.718281828459045
12.0
3628800
3.0
5
4
5.0

random Module — Dice & Card Games


■ random_module.py

import random

# Roll dice
def roll(sides=6, count=2):
return [[Link](1, sides) for _ in range(count)]

dice = roll(6, 2)
print(f"Rolled: {dice} Total: {sum(dice)}")

# Shuffle a deck
suits = ["♠","♥","♦","♣"]
ranks = ["A","2","3","4","5","6","7","8","9","10","J","Q","K"]
deck = [f"{r}{s}" for s in suits for r in ranks]
[Link](deck)
hand = deck[:5]
print("Your hand:", " ".join(hand))

# Random password
import string
chars = string.ascii_letters + [Link] + "!@#$"
pwd = "".join([Link](chars, k=12))
print("Password:", pwd)
Rolled: [4, 6] Total: 10
Your hand: 7♠ Q♥ 3♦ A♣ 9♠
Password: xK3!mB9qPz#w

datetime Module
■ datetime_module.py

from datetime import datetime, timedelta, date

now = [Link]()
today = [Link]()

print(f"Now: {[Link]('%Y-%m-%d %H:%M:%S')}")


print(f"Today: {today}")

# Age calculator
birthday = date(2000, 6, 15)
age_days = ([Link]() - birthday).days
print(f"Age: {age_days // 365} years ({age_days} days)")

# Deadline in 30 days
deadline = [Link]() + timedelta(days=30)
print(f"Deadline: {[Link]('%B %d, %Y')}")
Now: 2026-05-24 14:32:11
Today: 2026-05-24
Age: 25 years (9474 days)
Deadline: June 23, 2026

collections Module
■ collections_module.py

from collections import Counter, defaultdict, deque

# Counter — frequency analysis


words = "the quick brown fox jumps over the lazy dog the".split()
freq = Counter(words)
print(freq.most_common(3))

# defaultdict — no KeyError on missing keys


groups = defaultdict(list)
students = [("Math","Alice"),("Science","Bob"),("Math","Carol")]
for subject, name in students:
groups[subject].append(name)
print(dict(groups))

# deque — efficient queue


q = deque(["task1","task2","task3"])
[Link]("urgent")
print([Link]()) # urgent
[('the', 3), ('quick', 1), ('brown', 1)]
{'Math': ['Alice', 'Carol'], 'Science': ['Bob']}
urgent
CHAPTER 11

Advanced Functions
Decorators, generators, iterators & closures

■ Quick Summary

■ Closures: inner functions that remember their enclosing scope

■ Decorators: functions that wrap other functions to add behaviour

■ Generators: use yield to produce values one at a time (memory-efficient)

■ Iterators: any object with __iter__ and __next__

■ @[Link] preserves the wrapped function's metadata

Closures
■ [Link]

# A closure remembers the variable from its outer scope


def make_multiplier(factor):
def multiply(x):
return x * factor # "factor" is remembered
return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(10)) # 20
print(triple(10)) # 30

# Closure as a counter
def make_counter(start=0):
count = [start] # mutable so we can modify it
def counter():
count[0] += 1
return count[0]
return counter

c = make_counter()
print(c(), c(), c()) # 1 2 3
20
30
1 2 3
Decorators
■ [Link]

import time, functools

def timer(func):
"""Measure and print execution time."""
@[Link](func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} took {end-start:.4f}s")
return result
return wrapper

@timer
def slow_sum(n):
return sum(range(n))

print(slow_sum(1_000_000))
slow_sum took 0.0231s
499999500000
■ decorator_with_args.py — access control

def require_role(role):
def decorator(func):
@[Link](func)
def wrapper(user, *args, **kwargs):
if [Link]("role") != role:
raise PermissionError(f"Requires role: {role}")
return func(user, *args, **kwargs)
return wrapper
return decorator

@require_role("admin")
def delete_user(user, target):
return f"{user['name']} deleted {target}"

admin = {"name": "Alice", "role": "admin"}


guest = {"name": "Bob", "role": "guest"}

print(delete_user(admin, "Dave"))
try:
delete_user(guest, "Dave")
except PermissionError as e:
print(f"Blocked: {e}")
Alice deleted Dave
Blocked: Requires role: admin

Generators
■ [Link]

# Generator function — uses yield


def fibonacci(limit):
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b

print(list(fibonacci(100)))

# Generator expression (like list comp but lazy)


squares = (x**2 for x in range(1_000_000)) # no memory used yet!
print(next(squares)) # 0
print(next(squares)) # 1

# Infinite counter generator


def counter(start=0, step=1):
n = start
while True:
yield n
n += step

evens = counter(0, 2)
print([next(evens) for _ in range(5)]) # [0,2,4,6,8]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
0
1
[0, 2, 4, 6, 8]
CHAPTER 12

Comprehensions & Functional Tools


zip, map, filter, walrus operator

■ Quick Summary

■ List comp: [expr for x in iterable if condition]

■ Dict comp: {k: v for k, v in items}

■ Set comp: {expr for x in iterable}

■ zip pairs iterables element-by-element

■ map/filter are lazy — wrap in list() to see all values

■ Walrus operator := assigns and returns in one expression

Comprehensions — All Forms


■ [Link]

# List comprehension with condition


primes = [n for n in range(2, 50)
if all(n % d != 0 for d in range(2, n))]
print(primes)

# Dict comprehension — invert a dictionary


country_code = {"US":"United States","GB":"United Kingdom","DE":"Germany"}
code_country = {v: k for k, v in country_code.items()}
print(code_country["Germany"]) # DE

# Set comprehension — unique vowels


sentence = "the quick brown fox"
vowels = {ch for ch in sentence if ch in "aeiou"}
print(sorted(vowels))

# Nested comprehension — multiplication table


table = [[r*c for c in range(1,6)] for r in range(1,6)]
for row in table:
print(row)
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]
DE
['e','i','o','u']
[1,2,3,4,5]
[2,4,6,8,10]
...

zip, map, filter


■ functional_tools.py

# zip — combine two lists


names = ["Alice","Bob","Carol"]
scores = [92, 78, 88]
grades = ["A","C","B"]

report = list(zip(names, scores, grades))


for name, score, grade in report:
print(f" {name:8} {score} {grade}")

# map — apply function to every item


temps_c = [0, 20, 37, 100]
temps_f = list(map(lambda c: c*9/5+32, temps_c))
print(temps_f)

# filter — keep items matching condition


words = ["python","java","go","rust","javascript","c"]
long = list(filter(lambda w: len(w) > 4, words))
print(long)
Alice 92 A
Bob 78 C
Carol 88 B
[32.0, 68.0, 98.6, 212.0]
['python', 'javascript']

Walrus Operator :=
■ [Link]

# Without walrus — call len() twice


data = [1,2,3,4,5,6,7,8,9,10]
if len(data) > 5:
print(f"Long list: {len(data)} items")

# With walrus — compute once, use twice


if (n := len(data)) > 5:
print(f"Long list: {n} items")

# Walrus in while loop — process lines


import io
stream = [Link]("line1\nline2\nline3\n")
while chunk := [Link]():
print([Link]())
Long list: 10 items
Long list: 10 items
line1
line2
line3
CHAPTER 13

Practical Projects
Number game, password gen, data analyser, OOP bank

Project 1 — Advanced Number Guessing Game


■ number_game.py

import random

def play_game(max_num=100, max_attempts=7):


secret = [Link](1, max_num)
attempts = []

print(f"Guess a number between 1 and {max_num}.")


print(f"You have {max_attempts} attempts.\n")

for attempt in range(1, max_attempts + 1):


remaining = max_attempts - attempt
guess = int(input(f"Attempt {attempt}: "))
[Link](guess)

if guess == secret:
print(f"Correct! You won in {attempt} attempt(s)!")
return True, attempts
elif abs(guess - secret) <= 5:
hint = "Very warm" if guess < secret else "Very warm"
elif abs(guess - secret) <= 15:
hint = "Warm"
else:
hint = "Cold"
direction = "higher" if guess < secret else "lower"
print(f" {hint}! Go {direction}. {remaining} left.")

print(f"Game over! The number was {secret}.")


return False, attempts

play_game()
Guess a number 1-100. You have 7 attempts.
Attempt 1: 50
Cold! Go higher. 6 left.
Attempt 2: 75
Warm! Go lower. 5 left.
...

Project 2 — Password Generator


■ password_generator.py

import random, string

def generate_password(length=16, use_upper=True,


use_digits=True, use_symbols=True):
pool = string.ascii_lowercase
must_have = [[Link](string.ascii_lowercase)]

if use_upper:
pool += string.ascii_uppercase
must_have.append([Link](string.ascii_uppercase))
if use_digits:
pool += [Link]
must_have.append([Link]([Link]))
if use_symbols:
pool += "!@#$%^&*"
must_have.append([Link]("!@#$%^&*"))

remaining = [[Link](pool) for _ in range(length-len(must_have))]


password = must_have + remaining
[Link](password)
return "".join(password)

for i in range(5):
print(generate_password(16))
xK3!mB9qPz#wRt2Y
Aj@7vNpL!cQm3Xs9
...

Project 3 — Student Data Analyser


■ data_analyser.py

def analyse_grades(students):
"""Analyse a list of (name, grades_list) tuples."""
results = []
for name, grades in students:
avg = sum(grades) / len(grades)
[Link]({
"name": name,
"average": round(avg, 1),
"highest": max(grades),
"lowest": min(grades),
"grade": "A" if avg>=90 else "B" if avg>=80 else "C" if avg>=70 else "F
"
})

[Link](key=lambda r: r["average"], reverse=True)

print(f"{"NAME":<12}{"AVG":>6}{"HIGH":>6}{"LOW":>6} GRADE")
print("-" * 38)
for r in results:
print(f"{r['name']:<12}{r['average']:>6}{r['highest']:>6}{r['lowest']:>6} {r
['grade']}")

all_avgs = [r["average"] for r in results]


print(f"\nClass average: {sum(all_avgs)/len(all_avgs):.1f}")

data = [
("Alice", [92,88,95,91]), ("Bob", [72,68,75,80]),
("Carol", [88,92,85,90]), ("Dave", [60,55,70,65]),
]
analyse_grades(data)
NAME AVG HIGH LOW GRADE
--------------------------------------
Carol 88.8 92 85 B
Alice 91.5 95 88 A
Bob 73.8 80 68 C
Dave 62.5 70 55 F

Class average: 79.1

Project 4 — OOP Bank Account System


■ bank_system.py

from datetime import datetime

class Transaction:
def __init__(self, kind, amount, balance):
[Link] = kind
[Link] = amount
[Link] = balance
[Link] = [Link]().strftime("%H:%M:%S")
def __str__(self):
return f"[{[Link]}] {[Link]} ${[Link]:>8.2f} bal=${[Link]
e:.2f}"

class BankAccount:
def __init__(self, owner, balance=0):
[Link] = owner
self._balance = balance
self._history = []

@property
def balance(self):
return self._balance

def deposit(self, amount):


if amount <= 0: raise ValueError("Deposit must be positive")
self._balance += amount
self._history.append(Transaction("DEPOSIT", amount, self._balance))

def withdraw(self, amount):


if amount > self._balance: raise ValueError("Insufficient funds")
self._balance -= amount
self._history.append(Transaction("WITHDRAW", amount, self._balance))

def statement(self):
print(f"\n=== {[Link]}'s Account ===")
for t in self._history: print(t)
print(f"Current balance: ${self._balance:.2f}")

acc = BankAccount("Alice", 1000)


[Link](500)
[Link](200)
[Link](1200)
[Link]()
=== Alice's Account ===
[14:32:01] DEPOSIT $ 500.00 bal=$1500.00
[14:32:01] WITHDRAW $ 200.00 bal=$1300.00
[14:32:01] DEPOSIT $ 1200.00 bal=$2500.00
Current balance: $2500.00

■ Congratulations — You've Completed the Guide!

You now know variables, control flow, functions, OOP, modules, decorators, generators,
comprehensions, and file handling. Keep building — every project makes you stronger.

Next steps: explore pandas, Flask/Django, pytest, asyncio, and type hints. Practice daily on
[Link] or [Link].

You might also like