Python Cheatsheet
Comprehensive yet scannable notes with parameter details and method references.
1. Python Basics
- Interpreted: No compilation needed, runs directly
- Dynamically typed: Variable types determined at runtime
- Multi-paradigm: OOP, functional, procedural
- Run:
python filename.pyor use REPL:python/ipython
__name__ == "__main__" (⚠️ Common)
if __name__ == "__main__": main() # Only runs when script is executed directly- When run directly:
__name__="__main__"→ code inside runs - When imported:
__name__="module_name"→ code inside skipped
2. Variables & Data Types
Common types: int, float, str, bool, None, list, tuple, set, dict
Naming: snake_case; can't start with digit; avoid keywords like if, for, class
name = "Vedant" # strage = 21 # intprice = 9.99 # floatis_active = True # boolType conversion: int("42"), float("3.14"), str(100), bool(1)
Mutable vs Immutable (⚠️ Very Important)
| Mutable (Can Change) | Immutable (Cannot Change) |
|---|---|
list |
int, float, bool |
dict |
str |
set |
tuple |
frozenset |
|
None |
Why it matters:
# Immutable - creates new objects = "hello"s[0] = "H" # ❌ TypeError!
# Mutable - modifies same objectl = [1, 2, 3]l[0] = 99 # ✅ Works! l = [99, 2, 3]3. Operators
Arithmetic: + - * / // % **
//= floor division:7 // 2 = 3%= modulo (remainder):7 % 2 = 1**= power:2 ** 3 = 8
Comparison (Relational): == != > < >= <= → returns True/False
Logical: and, or, not
Membership: in, not in → check if item exists
Identity: is, is not → check if same object
5 > 3 and 2 < 4 # True'a' in 'apple' # Truex is None # True if x is NoneShort-Circuiting ⚡ (Important!)
Python stops evaluating as soon as result is determined
and Short-Circuit
- Returns first falsy value OR last value if all truthy
- Stops at first
False
False and expensive_function() # Returns False, function NOT calledTrue and True and False and print("Never runs") # Stops at False
0 and 5 # 0 (first falsy)3 and 5 # 5 (all truthy, returns last)1 and 2 and 3 # 3 (returns last truthy value)or Short-Circuit
- Returns first truthy value OR last value if all falsy
- Stops at first
True
True or expensive_function() # Returns True, function NOT calledFalse or False or True or print("Never runs") # Stops at True
0 or 5 # 5 (first truthy)0 or "" # "" (all falsy, returns last)1 or 2 or 3 # 1 (returns first truthy value)Practical Use Cases
# Default valuesname = user_input or "Guest" # If user_input is empty, use "Guest"
# Guard clausesif user and user.is_active and user.has_permission(): # Stops checking if user is None
# Conditional executionis_admin and send_admin_email() # Only calls if is_admin is TrueLogical Operators Truth Tables
| A | B | A and B | A or B | not A |
|---|---|---|---|---|
| T | T | T | T | F |
| T | F | F | T | F |
| F | T | F | T | T |
| F | F | F | F | T |
Quick Rules:
and→ True only if both are Trueor→ True if at least one is Truenot→ Reverses the boolean value
is vs == (⚠️ Common Trap)
| Operator | Checks | Use When |
|---|---|---|
== |
Value equality | Comparing values |
is |
Identity (same object) | Comparing with None |
a = [1, 2, 3]b = [1, 2, 3]c = a
a == b # True (same values)a is b # False (different objects in memory)a is c # True (same object)
# Always use 'is' for Nonex = Noneif x is None: # ✅ Correctif x == None: # ⚠️ Works but not PythonicInteger Caching (Tricky!):
a = 256; b = 256a is b # True (Python caches -5 to 256)
a = 257; b = 257a is b # False (outside cache range)4. Strings
Immutable, indexable: s[0], s[-1], s[1:4]
Slicing: s[start:end:step] → s[::-1] reverses string
Key String Methods
| Method | Syntax | Description |
|---|---|---|
upper() |
s.upper() |
Convert to UPPERCASE |
lower() |
s.lower() |
Convert to lowercase |
strip() |
s.strip() |
Remove leading/trailing whitespace |
lstrip() |
s.lstrip() |
Remove leading whitespace only |
rstrip() |
s.rstrip() |
Remove trailing whitespace only |
split() |
s.split(sep) |
Split by separator (default: space) |
join() |
sep.join(list) |
Join list items with separator |
replace() |
s.replace(old, new) |
Replace all occurrences |
find() |
s.find(sub) |
Find index (returns -1 if not found) |
index() |
s.index(sub) |
Find index (raises error if not found) |
count() |
s.count(sub) |
Count occurrences |
startswith() |
s.startswith(prefix) |
Check if starts with prefix |
endswith() |
s.endswith(suffix) |
Check if ends with suffix |
capitalize() |
s.capitalize() |
Capitalize first character |
title() |
s.title() |
Title Case Each Word |
isalpha() |
s.isalpha() |
Check if all alphabetic |
isdigit() |
s.isdigit() |
Check if all digits |
isalnum() |
s.isalnum() |
Check if alphanumeric |
islower() |
s.islower() |
Check if all lowercase |
isupper() |
s.isupper() |
Check if all uppercase |
isspace() |
s.isspace() |
Check if all whitespace |
s = "hello"; s[::-1] # 'olleh'"a,b,c".split(",") # ['a', 'b', 'c']"-".join(['a','b']) # 'a-b'String Formatting (3 Methods)
name, age = "Vedant", 21
# 1. f-strings (Python 3.6+) ✅ PREFERREDf"Name: {name}, Age: {age}" # "Name: Vedant, Age: 21"f"{age * 2}" # "42" (expressions allowed)f"{3.14159:.2f}" # "3.14" (formatting)
# 2. .format() method"Name: {}, Age: {}".format(name, age) # positional"Name: {n}, Age: {a}".format(n=name, a=age) # named
# 3. % operator (old style)"Name: %s, Age: %d" % (name, age)Common Format Specifiers:
| Specifier | Meaning | Example |
|---|---|---|
:.2f |
2 decimal places | f"{3.14159:.2f}" → "3.14" |
:05d |
Pad with zeros | f"{42:05d}" → "00042" |
:>10 |
Right align (10 chars) | f"{'hi':>10}" → " hi" |
:<10 |
Left align | f"{'hi':<10}" → "hi " |
:^10 |
Center align | f"{'hi':^10}" → " hi " |
5. Lists
Ordered, mutable sequence: can change after creation
Key List Methods
| Method | Syntax | Description |
|---|---|---|
append() |
l.append(item) |
Add item at end |
insert() |
l.insert(index, item) |
Insert at specific index |
extend() |
l.extend(iterable) |
Add multiple items |
remove() |
l.remove(item) |
Remove first occurrence |
pop() |
l.pop(index) |
Remove & return at index (default: -1) |
clear() |
l.clear() |
Remove all items |
index() |
l.index(item) |
Find index of first occurrence |
count() |
l.count(item) |
Count occurrences |
sort() |
l.sort(reverse=False) |
Sort in place |
reverse() |
l.reverse() |
Reverse in place |
copy() |
l.copy() |
Shallow copy of list |
l = [1, 2]; l.append(3) # [1, 2, 3]l.insert(1, 5) # [1, 5, 2, 3]l.extend([6, 7]) # [1, 5, 2, 3, 6, 7]l.pop() # removes 7, returns 7sorted(l) # returns sorted, doesn't modify l6. Tuples
Ordered, immutable: cannot change after creation
Use cases: fixed records, dictionary keys, unpacking
t = (1, 2, 3)a, b, c = t # unpackingt[0] # access: 1t.count(2) # count occurrencest.index(3) # find indexMethods: count(), index() only (immutable = fewer methods)
7. Sets
Unordered, unique elements: automatically removes duplicates
Fast membership checks: item in set is O(1)
Key Set Methods
| Method | Syntax | Description |
|---|---|---|
add() |
s.add(item) |
Add single element |
update() |
s.update(iterable) |
Add multiple elements |
remove() |
s.remove(item) |
Remove (error if not found) |
discard() |
s.discard(item) |
Remove (no error if not found) |
pop() |
s.pop() |
Remove random element |
clear() |
s.clear() |
Remove all elements |
union() |
s1.union(s2) or s1 | s2 |
All elements from both |
intersection() |
s1.intersection(s2) or s1 & s2 |
Common elements |
difference() |
s1.difference(s2) or s1 - s2 |
In s1 but not s2 |
symmetric_difference() |
s1.symmetric_difference(s2) or s1 ^ s2 |
In either but not both |
intersection_update() |
s1.intersection_update(s2) |
Update s1 with intersection (modifies s1) |
difference_update() |
s1.difference_update(s2) |
Update s1 with difference (modifies s1) |
symmetric_difference_update() |
s1.symmetric_difference_update(s2) |
Update s1 with symmetric diff (modifies s1) |
s = {1, 2, 2, 3} # {1, 2, 3} - auto removes duplicatess.add(4) # {1, 2, 3, 4}{1, 2} & {2, 3} # {2} - intersection
# Mutation variants (modify in place)s1 = {1, 2, 3}s1.intersection_update({2, 3, 4}) # s1 becomes {2, 3}8. Dictionaries
Key→value mapping: keys must be immutable (str, int, tuple)
Key Dictionary Methods
| Method | Syntax | Description |
|---|---|---|
get() |
d.get(key, default) |
Get value (no error if missing) |
keys() |
d.keys() |
View of all keys |
values() |
d.values() |
View of all values |
items() |
d.items() |
View of (key, value) pairs |
update() |
d.update(other_dict) |
Merge dictionaries |
pop() |
d.pop(key, default) |
Remove & return value |
popitem() |
d.popitem() |
Remove last inserted (k, v) |
clear() |
d.clear() |
Remove all items |
setdefault() |
d.setdefault(key, default) |
Get or set if missing |
fromkeys() |
dict.fromkeys(keys, value) |
Create dict from keys (class method) |
d = {'a': 1, 'b': 2}d.get('c', 0) # 0 (default)d.update({'c': 3}) # {'a': 1, 'b': 2, 'c': 3}for k, v in d.items(): print(k, v)
# fromkeys() - create dict with same value for all keyskeys = ['name', 'age', 'city']default_dict = dict.fromkeys(keys, 'N/A') # {'name': 'N/A', 'age': 'N/A', 'city': 'N/A'}zero_dict = dict.fromkeys(['a', 'b', 'c'], 0) # {'a': 0, 'b': 0, 'c': 0}9. Conditional Statements
if condition: # codeelif other_condition: # codeelse: # code
# Ternary operatorresult = value_if_true if condition else value_if_falseage = 20status = 'Adult' if age >= 18 else 'Minor'10. Loops
for Loop
Syntax: for item in iterable:
Use: Iterate over sequences (lists, strings, ranges, dicts)
for i in range(5): # 0, 1, 2, 3, 4for i in range(2, 7): # 2, 3, 4, 5, 6for i in range(0, 10, 2): # 0, 2, 4, 6, 8 (step=2)range() parameters: range(start=0, stop, step=1)
range(5)→ 0 to 4range(2, 5)→ 2, 3, 4range(0, 10, 2)→ 0, 2, 4, 6, 8
while Loop
while condition: # codeLoop Controls
break→ exit loop immediatelycontinue→ skip to next iterationelse→ executes if loop completes withoutbreak
for i in range(5): if i == 3: break print(i) # 0, 1, 211. Comprehensions
Fast, concise creation of lists/dicts/sets
# List comprehension[expression for item in iterable if condition]squares = [x**2 for x in range(5) if x % 2 == 0] # [0, 4, 16]
# Dict comprehension{key_expr: value_expr for item in iterable}{x: x**2 for x in range(3)} # {0: 0, 1: 1, 2: 4}
# Set comprehension{expression for item in iterable}{x % 3 for x in range(10)} # {0, 1, 2}12. Functions
Basic Syntax
def function_name(parameters): """Docstring: explains function""" # code return valueParameter Types
def func(a, b=10, *args, **kwargs): # a: positional # b: default value # *args: variable positional (tuple) # **kwargs: variable keyword (dict) pass
func(1) # a=1, b=10func(1, 20) # a=1, b=20func(1, 2, 3, 4) # a=1, b=2, args=(3, 4)func(1, x=5, y=10) # a=1, b=10, kwargs={'x': 5, 'y': 10}Lambda Functions
Anonymous functions: lambda args: expression
square = lambda x: x ** 2square(5) # 25
# With map/filterlist(map(lambda x: x*2, [1, 2, 3])) # [2, 4, 6]list(filter(lambda x: x > 2, [1, 2, 3, 4])) # [3, 4]Variable Scope
- Local: Inside function
- Global: Module level (use
globalkeyword to modify) - Enclosing: In nested functions (use
nonlocalfor nested)
x = 10 # globaldef modify(): global x x += 1 # modifies global x13. Iterators & Generators
Iterator vs Iterable
| Term | Definition | Example |
|---|---|---|
| Iterable | Has __iter__() method |
list, str, dict |
| Iterator | Has __iter__() AND __next__() |
iter([1,2,3]) |
# Creating iterator from iterablemy_list = [1, 2, 3]my_iter = iter(my_list) # Create iterator
next(my_iter) # 1next(my_iter) # 2next(my_iter) # 3next(my_iter) # StopIteration errorCustom Iterator
class Counter: def __init__(self, max): self.max = max self.current = 0
def __iter__(self): return self
def __next__(self): if self.current < self.max: self.current += 1 return self.current raise StopIteration
for num in Counter(3): print(num) # 1, 2, 3Generators (Simpler Way)
Use yield instead of return — pauses and resumes
def countdown(n): while n > 0: yield n # pauses here, returns value n -= 1
for num in countdown(3): print(num) # 3, 2, 1
# Generator expression (like list comprehension)gen = (x**2 for x in range(5)) # generator objectlist(gen) # [0, 1, 4, 9, 16]Why Generators?
- Memory efficient: Don't store all values at once
- Lazy evaluation: Compute values on-demand
- Infinite sequences: Can represent infinite data
# Infinite generatordef infinite_counter(): n = 0 while True: yield n n += 114. Decorators
Functions that modify other functions' behavior
Basic Decorator
def my_decorator(func): def wrapper(*args, **kwargs): print("Before function") result = func(*args, **kwargs) print("After function") return result return wrapper
@my_decoratordef say_hello(name): print(f"Hello, {name}!")
say_hello("Vedant")# Output:# Before function# Hello, Vedant!# After function@decorator is equivalent to: func = decorator(func)
Preserving Function Metadata with functools.wraps ⚠️
from functools import wraps
def my_decorator(func): @wraps(func) # ✅ Preserves __name__, __doc__, etc. def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper
@my_decoratordef greet(name): """Greet someone.""" return f"Hello, {name}!"
print(greet.__name__) # 'greet' (without @wraps: 'wrapper')print(greet.__doc__) # 'Greet someone.' (without @wraps: None)Decorator with Arguments
from functools import wraps
def repeat(times): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator
@repeat(times=3)def say_hello(): print("Hello!")
say_hello() # Prints "Hello!" 3 timesCommon Built-in Decorators
| Decorator | Purpose |
|---|---|
@staticmethod |
No self or cls access |
@classmethod |
Access cls (class) |
@property |
Getter method as attribute |
@abstractmethod |
Must be implemented by subclass |
@property Decorator
class Circle: def __init__(self, radius): self._radius = radius
@property def radius(self): # getter return self._radius
@radius.setter def radius(self, value): # setter if value > 0: self._radius = value
@property def area(self): # computed property return 3.14 * self._radius ** 2
c = Circle(5)c.radius # 5 (uses getter)c.radius = 10 # uses setterc.area # 314.0 (computed)15. OOP Basics
Class: Blueprint for objects
Instance: Actual object created from class__init__: Constructor (runs when creating object)self: Refers to instance itself
class Person: def __init__(self, name, age): self.name = name # instance variable self.age = age
def greet(self): return f"Hi, I'm {self.name}"
p = Person("Vedant", 21)p.greet() # "Hi, I'm Vedant"16. Inheritance & Method Overriding
Child class overrides parent method
Use super() to call parent implementation
class Parent: def greet(self): return "Hello from Parent"
class Child(Parent): def greet(self): parent_msg = super().greet() # call parent return f"{parent_msg} and Child"Inheritance Types
Single Inheritance
class Parent: passclass Child(Parent): # One parent passMultiple Inheritance
class A: passclass B: passclass C(A, B): # Multiple parents passMultilevel Inheritance
class Grandparent: passclass Parent(Grandparent): passclass Child(Parent): # Chain: Grandparent → Parent → Child passHierarchical Inheritance
class Parent: passclass Child1(Parent): # Multiple children, one parent passclass Child2(Parent): passHybrid Inheritance
Combination of two or more inheritance types.
MRO (Method Resolution Order) ⚠️ Important
class A: def show(self): print("A")class B(A): def show(self): print("B")class C(A): def show(self): print("C")class D(B, C): # Diamond problem pass
print(D.mro()) # [D, B, C, A, object]D().show() # "B" (follows MRO: left to right)MRO Rule: Left-to-right, depth-first, but each class appears only once.
17. Encapsulation
Control access using naming conventions:
public→ normal:self.name_protected→ convention:self._name(still accessible)__private→ name mangling:self.__name(harder to access)
class BankAccount: def __init__(self, balance): self.__balance = balance # private
def get_balance(self): # getter return self.__balance
def deposit(self, amount): # setter with validation if amount > 0: self.__balance += amount18. Abstraction
Hide implementation details, show only necessary interface
Use abc module for abstract base classes
from abc import ABC, abstractmethod
class Shape(ABC): @abstractmethod def area(self): pass # must be implemented by subclass
class Circle(Shape): def __init__(self, radius): self.radius = radius
def area(self): # implementation return 3.14 * self.radius ** 219. Polymorphism
Same interface, different implementations
Duck typing: "If it quacks like a duck..."
class Dog: def speak(self): return "Woof"
class Cat: def speak(self): return "Meow"
for animal in [Dog(), Cat()]: print(animal.speak()) # Different behavior, same method20. Instance/Class/Static Methods
class MyClass: class_var = 10 # class variable
def instance_method(self): # has access to self (instance) return self.class_var
@classmethod def class_method(cls): # has access to cls (class) return cls.class_var
@staticmethod def static_method(): # no access to self or cls return "static"21. Dunder/Magic Methods
Double underscore methods that Python calls automatically.
Most Important Dunder Methods
| Method | Called When | Example |
|---|---|---|
__init__(self) |
Object created | obj = MyClass() |
__str__(self) |
str(obj) or print(obj) |
Human-readable |
__repr__(self) |
repr(obj) or in REPL |
Developer-readable |
__len__(self) |
len(obj) |
Return length |
__eq__(self, other) |
obj1 == obj2 |
Equality check |
__lt__(self, other) |
obj1 < obj2 |
Less than |
__add__(self, other) |
obj1 + obj2 |
Addition |
__getitem__(self, key) |
obj[key] |
Indexing |
__setitem__(self, key, val) |
obj[key] = val |
Assignment |
__iter__(self) |
for x in obj |
Make iterable |
__call__(self) |
obj() |
Make callable |
class Book: def __init__(self, title, pages): self.title = title self.pages = pages
def __str__(self): # for print() return f"{self.title}"
def __repr__(self): # for debugging return f"Book('{self.title}', {self.pages})"
def __len__(self): # for len() return self.pages
def __eq__(self, other): # for == return self.title == other.title
b = Book("Python", 300)print(b) # Python (__str__)len(b) # 300 (__len__)22. File Handling
File Modes
| Mode | Description | Creates if missing? |
|---|---|---|
'r' |
Read (default) | No, error if not found |
'w' |
Write (overwrites) | Yes |
'a' |
Append | Yes |
'r+' |
Read + Write | No |
'b' |
Binary mode | Add to others (e.g., 'rb') |
File Methods
| Method | Description |
|---|---|
read() |
Read entire file |
read(n) |
Read n characters |
readline() |
Read one line |
readlines() |
Read all lines as list |
write(text) |
Write text |
writelines(list) |
Write list of strings |
close() |
Close file (auto with with) |
# Best practice: with statement (auto-closes)with open('file.txt', 'r') as f: data = f.read()
# Writingwith open('output.txt', 'w') as f: f.write("Hello World\n")23. Exception Handling
try: # code that might raise exception result = 10 / 0except ZeroDivisionError as e: # handle specific exception print(f"Error: {e}")except Exception as e: # handle any exception print(f"General error: {e}")else: # runs if no exception print("Success!")finally: # always runs (cleanup) print("Cleanup")
# Raise exceptionsraise ValueError("Invalid value")Common exceptions: ValueError, TypeError, KeyError, IndexError, ZeroDivisionError, FileNotFoundError
Exception Groups (Python 3.11+)
# Raise multiple exceptions at oncedef process_items(items): errors = [] for item in items: try: validate(item) except ValueError as e: errors.append(e) if errors: raise ExceptionGroup("Validation failed", errors)
# Handle with except*try: process_items([1, -1, "bad"])except* ValueError as eg: print(f"Value errors: {eg.exceptions}")except* TypeError as eg: print(f"Type errors: {eg.exceptions}")Custom Exceptions
class ValidationError(Exception): def __init__(self, field: str, message: str): self.field = field self.message = message super().__init__(f"{field}: {message}")
raise ValidationError("email", "Invalid format")24. Shallow vs Deep Copy
The Problem
original = [[1, 2], [3, 4]]shallow = original.copy() # or list(original)
shallow[0][0] = 99print(original) # [[99, 2], [3, 4]] ← Original also changed!Solution: Deep Copy
import copy
original = [[1, 2], [3, 4]]deep = copy.deepcopy(original)
deep[0][0] = 99print(original) # [[1, 2], [3, 4]] ← Original unchanged!Comparison Table
| Type | Syntax | Nested Objects | Use When |
|---|---|---|---|
| Assignment | b = a |
Same object | Aliasing |
| Shallow Copy | a.copy(), list(a), a[:] |
Shared (reference) | Flat structures |
| Deep Copy | copy.deepcopy(a) |
Independent copies | Nested structures |
import copy
a = [1, [2, 3]]
# Assignment (alias)b = ab is a # True (same object)
# Shallow copyc = a.copy()c is a # False (different list)c[1] is a[1] # True (nested list shared!)
# Deep copyd = copy.deepcopy(a)d is a # Falsed[1] is a[1] # False (completely independent)25. Type Hints
Static type annotations for better code documentation and IDE support.
Basic Type Hints
# Variablesname: str = "Vedant"age: int = 21price: float = 9.99is_active: bool = True
# Functionsdef greet(name: str) -> str: return f"Hello, {name}!"
def add(a: int, b: int) -> int: return a + b
# None return typedef log(message: str) -> None: print(message)Collection Type Hints
# Use built-in types directly (Python 3.10+)numbers: list[int] = [1, 2, 3]scores: dict[str, int] = {"alice": 100}coords: tuple[int, int] = (10, 20)unique: set[str] = {"a", "b"}
# Nested collectionsmatrix: list[list[int]] = [[1, 2], [3, 4]]user_data: dict[str, list[int]] = {"scores": [90, 85, 88]}Optional & Union (Python 3.10+ syntax)
# Optional = can be None (use | None)def find_user(id: int) -> str | None: return None if id < 0 else "User"
# Union = multiple possible types (use |)def process(value: int | str) -> str: return str(value)
# Multiple typesdef handle(data: int | float | str | None) -> str: return str(data) if data else "Empty"Callable & TypeVar
from typing import Callable, TypeVar
# Function type hintsdef apply(func: Callable[[int, int], int], a: int, b: int) -> int: return func(a, b)
# Generic type variableT = TypeVar('T')def first(items: list[T]) -> T: return items[0]Type Aliases
type Vector = list[float] # Python 3.12+ syntaxtype Matrix = list[Vector]
# Python 3.10-3.11from typing import TypeAliasVector: TypeAlias = list[float]Matrix: TypeAlias = list[Vector]
def scale(v: Vector, factor: float) -> Vector: return [x * factor for x in v]Self Type (Python 3.11+)
from typing import Self
class Builder: def set_name(self, name: str) -> Self: self.name = name return self # Enables method chaining
def set_age(self, age: int) -> Self: self.age = age return self
# Usagebuilder = Builder().set_name("Vedant").set_age(21)26. Dataclasses
Automatic generation of __init__, __repr__, __eq__, etc.
Basic Dataclass
from dataclasses import dataclass
@dataclassclass Person: name: str age: int email: str = "" # default value
# Auto-generated __init__, __repr__, __eq__p = Person("Vedant", 21)print(p) # Person(name='Vedant', age=21, email='')
p1 = Person("Vedant", 21)p2 = Person("Vedant", 21)p1 == p2 # True (auto __eq__)Dataclass Options
from dataclasses import dataclass, field
@dataclass(frozen=True) # Immutable (hashable)class Point: x: int y: int
@dataclass(order=True) # Adds comparison methodsclass Student: name: str grade: float
@dataclass(slots=True) # Memory efficient (Python 3.10+)class User: name: str age: int # Uses __slots__ instead of __dict__ → less memory, faster access
# Mutable default values - use field()@dataclassclass Team: name: str members: list = field(default_factory=list) # ✅ Correct # members: list = [] # ❌ WRONG! Same mutable default trapDataclass Options Reference
| Option | Default | Purpose |
|---|---|---|
frozen |
False |
Make immutable (hashable) |
order |
False |
Add <, >, <=, >= methods |
slots |
False |
Use __slots__ for memory efficiency |
kw_only |
False |
All fields keyword-only (3.10+) |
match_args |
True |
Enable pattern matching support |
Post-Init Processing
from dataclasses import dataclass, field
@dataclassclass Rectangle: width: float height: float area: float = field(init=False) # Not in __init__
def __post_init__(self): self.area = self.width * self.height
r = Rectangle(10, 5)r.area # 50.0 (computed automatically)Dataclass vs NamedTuple vs Regular Class
| Feature | @dataclass |
NamedTuple |
Regular Class |
|---|---|---|---|
| Mutable | ✅ (default) | ❌ | ✅ |
Auto __init__ |
✅ | ✅ | ❌ |
Auto __repr__ |
✅ | ✅ | ❌ |
| Type hints | ✅ Required | ✅ Required | Optional |
| Inheritance | ✅ | Limited | ✅ |
| Memory | Normal | Optimized | Normal |
27. Match Statement
Structural pattern matching — like switch/case on steroids.
Basic Match
def http_status(status: int) -> str: match status: case 200: return "OK" case 404: return "Not Found" case 500: return "Server Error" case _: # default (wildcard) return "Unknown"
http_status(200) # "OK"http_status(999) # "Unknown"Pattern Matching with OR
match status: case 200 | 201 | 204: # Multiple values return "Success" case 400 | 401 | 403 | 404: return "Client Error" case _: return "Other"Matching Sequences
def analyze(point): match point: case (0, 0): return "Origin" case (0, y): # Capture y return f"On Y-axis at {y}" case (x, 0): # Capture x return f"On X-axis at {x}" case (x, y): # Capture both return f"Point at ({x}, {y})" case _: return "Not a point"
analyze((0, 5)) # "On Y-axis at 5"Matching Dictionaries
def process_event(event: dict): match event: case {"type": "click", "x": x, "y": y}: return f"Click at ({x}, {y})" case {"type": "keypress", "key": key}: return f"Key pressed: {key}" case {"type": type_}: # Capture unknown type return f"Unknown event: {type_}"Matching with Guards
match point: case (x, y) if x == y: return "On diagonal" case (x, y) if x > 0 and y > 0: return "First quadrant" case (x, y): return f"Point at ({x}, {y})"Matching Classes
@dataclassclass Point: x: int y: int
def locate(point): match point: case Point(x=0, y=0): return "Origin" case Point(x=0, y=y): return f"Y-axis at {y}" case Point(x=x, y=0): return f"X-axis at {x}" case Point(): return "Somewhere else"28. Walrus Operator :=
Assignment expression — assign and use in one expression.
Basic Usage
# Without walrus operatordata = get_data()if data: process(data)
# With walrus operator ✅if (data := get_data()): process(data)Common Use Cases
# 1. While loops with assignmentwhile (line := file.readline()): process(line)
# 2. List comprehensions with expensive computation# Without walrus - calls compute() twice:[compute(x) for x in data if compute(x) > 0]
# With walrus - calls compute() once: ✅[y for x in data if (y := compute(x)) > 0]
# 3. Regex matchingimport reif (match := re.search(r'\d+', text)): print(f"Found: {match.group()}")
# 4. Avoiding repeated dictionary lookupsif (value := my_dict.get('key')) is not None: process(value)When NOT to Use ⚠️
# Don't use for simple assignmentsx := 5 # ❌ SyntaxError! Must be in parentheses or expression
# Don't overuse - readability mattersresult = (a := 1) + (b := 2) + (c := 3) # ⚠️ Hard to read
# Keep it simplea, b, c = 1, 2, 3 # ✅ Clearerresult = a + b + c29. Context Managers (with Statement)
Automatic resource management — ensures cleanup even if errors occur.
Built-in Context Managers
# File handling (auto-closes)with open('file.txt', 'r') as f: data = f.read()# f is automatically closed here
# Multiple context managerswith open('in.txt') as f_in, open('out.txt', 'w') as f_out: f_out.write(f_in.read())
# Threading locksimport threadinglock = threading.Lock()with lock: # Critical section passCreating Context Managers
Method 1: Class-based (__enter__ / __exit__)
class Timer: def __enter__(self): import time self.start = time.time() return self # Returned to 'as' variable
def __exit__(self, exc_type, exc_val, exc_tb): import time self.end = time.time() print(f"Elapsed: {self.end - self.start:.2f}s") return False # Don't suppress exceptions
with Timer() as t: # code to time passMethod 2: Generator-based (@contextmanager) ✅ Simpler
from contextlib import contextmanager
@contextmanagerdef timer(): import time start = time.time() try: yield # Code inside 'with' runs here finally: end = time.time() print(f"Elapsed: {end - start:.2f}s")
with timer(): # code to time pass__exit__ Parameters
def __exit__(self, exc_type, exc_val, exc_tb): # exc_type: Exception class (e.g., ValueError) # exc_val: Exception instance # exc_tb: Traceback object
if exc_type is ValueError: print("Caught ValueError, suppressing...") return True # Suppress the exception return False # Re-raise any other exception30. Async/Await
Asynchronous programming for I/O-bound concurrent tasks.
Basic Concepts
| Term | Meaning |
|---|---|
async def |
Defines a coroutine function |
await |
Pause until coroutine completes |
asyncio |
Standard library for async I/O |
| Coroutine | Object returned by async function |
| Event Loop | Runs and manages coroutines |
Basic Async Function
import asyncio
async def fetch_data(): print("Fetching...") await asyncio.sleep(2) # Non-blocking sleep print("Done!") return {"data": 123}
# Running the coroutineasync def main(): result = await fetch_data() print(result)
asyncio.run(main()) # Entry pointRunning Tasks Concurrently
import asyncio
async def task(name, delay): print(f"{name} starting") await asyncio.sleep(delay) print(f"{name} done") return name
async def main(): # Run concurrently (not sequentially!) results = await asyncio.gather( task("A", 2), task("B", 1), task("C", 3) ) print(results) # ['A', 'B', 'C']
asyncio.run(main()) # Total time: ~3s (not 6s)Creating Tasks
async def main(): # Create task (starts immediately) task1 = asyncio.create_task(fetch_data()) task2 = asyncio.create_task(fetch_data())
# Do other work while tasks run...
# Wait for results result1 = await task1 result2 = await task2Async Context Managers & Iterators
# Async context managerasync with aiohttp.ClientSession() as session: async with session.get(url) as response: data = await response.text()
# Async iteratorasync for item in async_generator(): process(item)When to Use Async ⚠️
| Use Async For | Don't Use Async For |
|---|---|
| Network I/O (HTTP, databases) | CPU-bound tasks |
| File I/O (with async libs) | Simple scripts |
| Many concurrent connections | Single operations |
| Web servers/APIs | Heavy computations |
For CPU-bound: Use multiprocessing or concurrent.futures.ProcessPoolExecutor
31. Common Traps
Mutable Default Arguments ⚠️
def bad_func(items=[]): # ❌ WRONG! items.append(1) return items
bad_func() # [1]bad_func() # [1, 1] ← Same list reused!
def good_func(items=None): # ✅ CORRECT if items is None: items = [] items.append(1) return itemsList Aliasing
a = [1, 2, 3]b = a # b is alias (same object)b.append(4)print(a) # [1, 2, 3, 4] ← a also changed!
# Fix: Create copyb = a.copy() # or a[:] or list(a)Integer Caching
a = 256; b = 256a is b # True (cached: -5 to 256)
a = 257; b = 257a is b # False (outside cache)a == b # True (values equal)String Immutability
s = "hello"s[0] = "H" # ❌ TypeError! Strings are immutables = "H" + s[1:] # ✅ Create new stringfor Loop Variable Scope
for i in range(3): passprint(i) # 2 ← Variable exists after loop!Truthy/Falsy Values
# Falsy values (evaluate to False)bool(0) # Falsebool(0.0) # Falsebool("") # False (empty string)bool([]) # False (empty list)bool({}) # False (empty dict)bool(None) # False
# Everything else is Truthybool(1) # Truebool("hello") # Truebool([0]) # True (non-empty list)pass vs continue vs break
| Keyword | Purpose |
|---|---|
pass |
Do nothing (placeholder) |
continue |
Skip to next iteration |
break |
Exit loop entirely |
Dictionary Key Overwriting
d = {'a': 1, 'a': 2} # Duplicate key!print(d) # {'a': 2} ← Last value wins32. Quick Reference
Useful Snippets
# Swapa, b = b, a
# Check emptyif not my_list: # True if empty
# Reverses[::-1]
# Merge dicts (Python 3.9+){**dict1, **dict2} # or: dict1 | dict2
# Unique elements (preserve order)list(dict.fromkeys(seq))
# Flatten nested list[item for sublist in nested for item in sublist]
# Enumerate with indexfor i, item in enumerate(my_list): print(i, item)
# Zip two listslist(zip([1, 2], ['a', 'b'])) # [(1, 'a'), (2, 'b')]
# Any/Allany([False, True, False]) # True (at least one True)all([True, True, False]) # False (not all True)
# Get with defaultvalue = my_dict.get('key', 'default')
# Conditional expressionresult = 'yes' if condition else 'no'
# Safe divisionresult = a // b if b else 0
# Group by key (must sort by same key first!)from itertools import groupbykey_func = lambda x: x[0]{k: list(v) for k, v in groupby(sorted(items, key=key_func), key=key_func)}Useful Standard Library Modules (Python 3.11+)
# tomllib - Parse TOML files (Python 3.11+)import tomllibwith open("config.toml", "rb") as f: config = tomllib.load(f)
# pathlib - Modern file pathsfrom pathlib import Pathpath = Path("dir") / "file.txt" # Cross-platformpath.read_text() # Read filepath.exists() # Check existencelist(Path(".").glob("*.py")) # Find files
# functools - Function utilitiesfrom functools import cache, partial@cache # Memoization (simpler than lru_cache)def fib(n): return n if n < 2 else fib(n-1) + fib(n-2)
# itertools - Iterator utilitiesfrom itertools import chain, groupby, combinationslist(chain([1,2], [3,4])) # [1, 2, 3, 4]list(combinations([1,2,3], 2)) # [(1,2), (1,3), (2,3)]
# collections - Specialized containersfrom collections import Counter, defaultdict, dequeCounter("hello") # {'l': 2, 'h': 1, 'e': 1, 'o': 1}defaultdict(list) # Dict with default factorydeque([1,2,3], maxlen=3) # Fixed-size queue