# Basics
# initialize
d = {'a': 1, 'c': 7, 'd': 'prime'}
d2 = dict()
# add
d2['a'] = 1
# delete
del d['d']
# get keys and values
print(list(d.items())) # [('a', 1), ('c', 7)]
print(list(d2.items())) # [('a', 1)]
# convert the iterables to lists
print(list(d.keys())) # ['a', 'c']
print(list(d.values())) # [1, 7]
# Get value with default
d = {'a': 1}
# get value
print(d['a']) # 1
# get value with default value (see defaultdict as well)
print(d.get('a', 0)) # 1
print(d.get('b', 0)) # 0
Set
# Set operations
a = {1, 2, 3}
b = set([2, 3, 4])
print(a & b) # {2, 3}
print(a | b) # {1, 2, 3, 4}
print(a - b) # {1}
# Set add and remove
s = set()
s.add(1)
s.add(2)
s.remove(1)
print(s) # {2}
s.discard(7)
print(s) # {2}
print(s.pop()) # 2
s.remove(7) # KeyError: 7
Enumeration
# Enumerate
fruits = ['apple', 'banana', 'cherry']
for i, fruit in enumerate(fruits):
print(i, fruit)
# 0 apple
# 1 banana
# 2 cherry
Zip Function
# Using zip
names = ['a', 'b', 'c']
scores = [100, 90, 50]
print(zip(names, scores)) # zip object
print(list(zip(names, scores))) # [('a', 100), ('b', 90), ('c', 50)]
for name, score in zip(names, scores):
print(name, score)
# a 100
# b 90
# c 50
Comprehension
# Dictionary comprehension
numbers = [1, 2, 3, 4, 5]
squared_dict = {n: n**2 for n in numbers if n % 2 == 0}
print(squared_dict) # {2: 4, 4: 16}
# Set comprehension
words = ["hello", "world", "hello", "python"]
unique_lengths = {len(word) for word in words}
print(unique_lengths) # {5, 6}
# Nested list comprehension
matrix = [[1, 2, 3], [4, 5, 6]]
flattened = [num for row in matrix for num in row]
print(flattened) # [1, 2, 3, 4, 5, 6]
# Generator comprehension
numbers = (x**2 for x in range(5))
print(sum(numbers)) # 30
print(type(numbers)) # class 'generator'
# List comprehension with filtering
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [x for x in numbers if x % 2 == 0]
squares_of_odds = [x**2 for x in numbers if x % 2 == 1]
print(evens) # [2, 4, 6, 8, 10]
print(squares_of_odds) # [1, 9, 25, 49, 81]
# Multiple conditions in comprehensions
data = [("Alice", 85, "A"), ("Bob", 92, "A"), ("Charlie", 76, "B")]
high_achievers = [name for name, score, grade in data if score > 80 and grade == "A"]
print(high_achievers) # ['Alice', 'Bob']
# Nested comprehension with condition
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened_evens = [num for row in matrix for num in row if num % 2 == 0]
print(flattened_evens) # [2, 4, 6, 8]
# Dict comprehension with if else conditional values
temperatures = {"Mon": 75, "Tue": 68, "Wed": 82, "Thu": 71}
comfort_levels = {day: "warm" if temp > 75 else "cool" for day, temp in temperatures.items()}
print(comfort_levels) # {'Mon': 'cool', 'Tue': 'cool', 'Wed': 'warm', 'Thu': 'cool'}
# Complex conditional transformation
people = [("Alice", 25), ("Bob", 17), ("Charlie", 30)]
status = {name: "adult" if age >= 18 else "minor" for name, age in people}
print(status) # {'Alice': 'adult', 'Bob': 'minor', 'Charlie': 'adult'}
# Combining filtering and conditional transformation
numbers = [-3, -1, 0, 2, 4, -2, 5]
# Only process positive numbers, square them if even, cube if odd
result = [x**2 if x % 2 == 0 else x**3 for x in numbers if x > 0]
print(result) # [4, 16, 125]
# Set comprehension with conditional values
words = ["apple", "banana", "cherry", "date"]
modified = {word.upper() if len(word) > 5 else word.lower() for word in words}
print(modified) # {'apple', 'BANANA', 'CHERRY', 'date'}
Variable Assignment with If Else
# Ternary operator
age = 25
status = "adult" if age >= 18 else "minor"
print(status) # adult
# Nested ternary operators
score = 85
grade = "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "F"
print(grade) # B
# With function calls
numbers = [1, 2, 3, 4, 5]
result = max(numbers) if numbers else 0
print(result) # 5
# Ternary in list/dict assignments
temperature = 75
clothing = ["shorts", "t-shirt"] if temperature > 70 else ["pants", "jacket"]
print(clothing) # ['shorts', 't-shirt']
weather_config = {"AC": "on"} if temperature > 75 else {"heater": "on"}
print(weather_config) # {'heater': 'on'}
Loop Control
# Break and continue in nested loops
for i in range(3):
for j in range(3):
if i == 1 and j == 1:
continue
if i == 2:
break
print(f"({i}, {j})")
# (0, 0), (0, 1), (0, 2), (1, 0), (1, 2)
# Loop with else clause
for i in range(3):
if i == 5: # Never true
break
else:
print("Loop completed normally") # This prints
for i in range(3):
if i == 1:
break
else:
print("This won't print")
# While loop with break/continue
count = 0
while count < 10:
count += 1
if count % 2 == 0:
continue
if count > 7:
break
print(count) # Prints 1, 3, 5, 7
Unpacking with * and **
# Basic tuple/list unpacking
point = (3, 4)
x, y = point
print(x + y) # 7
coordinates = [10, 20, 30]
x, y, z = coordinates
print(f"x={x}, y={y}, z={z}") # x=10, y=20, z=30
# * unpacking in function calls
def add_three(a, b, c):
return a + b + c
numbers = [1, 2, 3]
result = add_three(*numbers) # Same as add_three(1, 2, 3)
print(result) # 6
# * unpacking for collecting remaining values
data = [1, 2, 3, 4, 5]
first, *middle, last = data
print(f"first: {first}") # first: 1
print(f"middle: {middle}") # middle: [2, 3, 4]
print(f"last: {last}") # last: 5
# *args and **kwargs in function definitions REPACK
# new args tuple and kwargs dictionary are available for internal use
def flexible_func(*args, **kwargs):
print(f"Positional args: {args}")
print(f"Keyword args: {kwargs}")
flexible_func(1, 2, 3, name="Alice", age=25)
# Positional args: (1, 2, 3)
# Keyword args: {'name': 'Alice', 'age': 25}
# Unpacking with enumerate and zip
data = ['a', 'b', 'c']
numbers = [1, 2, 3]
# Unpack enumerate results
for i, letter in enumerate(data):
print(f"{i}: {letter}")
# Unpack zip results
for letter, num in zip(data, numbers):
print(f"{letter} = {num}") # a = 1, b = 2, c = 3
# Advanced unpacking patterns
# Ignore values with *_
numbers = [1, 2, 3, 4, 5, 6]
first, second, *_ = numbers
print(f"first: {first}, second: {second}") # first: 1, second: 2
# Multiple * unpacking in one expression
a, b = [1, 2], [3, 4]
result = [*a, 0, *b]
print(result) # [1, 2, 0, 3, 4]
# Unpacking nested structures
nested = [(1, 2), (3, 4), (5, 6)]
for x, y in nested:
print(f"x={x}, y={y}")
# Unpacking dictionary items
person = {"name": "Bob", "age": 30}
for key, value in person.items():
print(f"{key}: {value}")
# Convert range to list using *
numbers = [*range(5)]
print(numbers) # [0, 1, 2, 3, 4]
# Unpack string into characters
word = "hello"
chars = [*word]
print(chars) # ['h', 'e', 'l', 'l', 'o']
# Unpacking in list/dict comprehensions
pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
numbers = [num for num, _ in pairs]
letters = [letter for _, letter in pairs]
print(numbers) # [1, 2, 3]
print(letters) # ['a', 'b', 'c']
# Create dict from unpacked pairs
result = {num: letter for num, letter in pairs}
print(result) # {1: 'a', 2: 'b', 3: 'c'}
# Custom datetime formatting
from datetime import datetime
now = datetime.now()
print(now.strftime("%A, %B %d, %Y at %I:%M %p"))
print(now.strftime("Week %U of %Y")) # Week number
print(now.strftime("%j")) # Day of year
Functional Tools
# Use map and lambda
nums = [1, 2, 3]
doubled = list(map(lambda x: x * 2, nums))
print(doubled) # [2, 4, 6]
# Bitwise operations
a = 5 # 0b101
b = 3 # 0b011
print(a & b) # 1
print(a | b) # 7
print(a ^ b) # 6
print(a << 1) # 10
print(a >> 1) # 2
# Count set bits
n = 29 # 0b11101
print(bin(n).count('1')) # 4
Stack and Queue
# Using deque (double-ended queue) as stack and queue
from collections import deque
dq = deque()
dq.append(1) # push to right
dq.appendleft(2) # push to left
print(dq.pop()) # 1
print(dq.popleft()) # 2
any() and all()
# Generator expression with any() and all()
nums = [1, 3, 5, 18]
gen = (x % 2 == 1 for x in nums)
print(gen) # generator object
for bool in gen:
print(bool) # True True True False
print(any(x % 2 == 0 for x in nums)) # True
print(any((x % 2 == 0 for x in nums))) # True
print(all(x < 10 for x in nums)) # False
print(any([2, 4, 5])) # True
# LRU Cache with limited size showing eviction
from functools import lru_cache
# Small cache size to demonstrate eviction
@lru_cache(maxsize=3)
def expensive_computation(x):
"""Simulate an expensive computation"""
print(f" → Computing result for {x}")
return x * x * x # Cube the number
# Function to show cache info
def show_cache_info():
info = expensive_computation.cache_info()
print(f"Cache: hits={info.hits}, misses={info.misses}, "
f"current_size={info.currsize}, max_size={info.maxsize}")
print("=== LRU Cache Eviction Demo ===")
print("Cache size limit: 3 items")
print()
# Fill the cache completely
print("1. Filling cache to capacity:")
for i in [1, 2, 3]:
result = expensive_computation(i)
print(f" expensive_computation({i}) = {result}")
show_cache_info()
print()
# Access items to show cache hits
print("2. Accessing cached items (no computation needed):")
for i in [1, 2, 3]:
result = expensive_computation(i)
print(f" expensive_computation({i}) = {result} (cached)")
show_cache_info()
print()
# Add new item - should evict least recently used (1)
print("3. Adding new item (will evict LRU item):")
result = expensive_computation(4)
print(f" expensive_computation(4) = {result}")
show_cache_info()
print()
# Try to access evicted item - should recompute
print("4. Accessing evicted item (needs recomputation):")
result = expensive_computation(1)
print(f" expensive_computation(1) = {result}")
show_cache_info()
print()
# Clear cache
expensive_computation.cache_clear()
print("5. Cache cleared")
show_cache_info()
OrderedDict and namedtuple
# OrderedDict maintains insertion order
from collections import OrderedDict
od = OrderedDict()
od['first'] = 1
od['second'] = 2
od['third'] = 3
print(list(od.keys())) # ['first', 'second', 'third']
# namedtuple creates tuple subclass with named fields
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y) # 3 4
print(p._asdict()) # {'x': 3, 'y': 4}
Defaultdict and Counter
# Using defaultdict for grouping
from collections import defaultdict
groups = defaultdict(list)
words = ["bat", "tab", "cat"]
for word in words:
groups["".join(sorted(word))].append(word)
print(groups) # {'abt': ['bat', 'tab'], 'act': ['cat']}
# Using Counter for frequency
from collections import Counter
nums = [1, 2, 2, 3, 3, 3]
count = Counter(nums)
print(count) # Counter({3: 3, 2: 2, 1: 1})
print(count[2]) # 2
# Sort by custom key (length of string)
words = ["a", "abc", "ab"]
words.sort(key=len)
print(words) # ['a', 'ab', 'abc']
# Sorting by multiple criteria
pairs = [[1, 3], [2, 2], [1, 2]]
pairs.sort(key=lambda x: (x[0], -x[1])) # first by the 0th element, then by the negative of the second element
print(pairs) # [[1, 3], [1, 2], [2, 2]]
# Using reversed() with different data types
# Reverse a string
text = "hello"
reversed_text = ''.join(reversed(text))
print("Reversed string:", reversed_text) # olleh
# Reverse a tuple (creates list)
colors = ("red", "green", "blue")
reversed_colors = list(reversed(colors))
print("Reversed tuple:", reversed_colors) # ['blue', 'green', 'red']
# Combining reverse with other operations
numbers = [1, 2, 3, 4, 5, 6]
# Sort then reverse
sorted_desc = sorted(numbers, reverse=True)
print("Sorted descending:", sorted_desc) # [6, 5, 4, 3, 2, 1]
# Reverse then process
words = ["python", "java", "ruby"]
for word in reversed(words):
print(word.upper()) # RUBY, JAVA, PYTHON
# Slice notation for reversal (alternative)
slice_reversed = numbers[::-1]
print("Slice reversed:", slice_reversed) # [6, 5, 4, 3, 2, 1]
ord() Function and Character-Based Sorting
# Basic ord() usage - converts character to ASCII value
print(ord('A')) # 65
print(ord('a')) # 97
print(ord('0')) # 48
print(ord(' ')) # 32
# Compare characters using ord()
char1, char2 = 'b', 'a'
print(f"'{char1}' comes after '{char2}':", ord(char1) > ord(char2)) # True
# Sorting names: alphabetical by first letter of first name, reverse alphabetical by first letter of last name
names = [("John", "Smith"), ("Alice", "Johnson"), ("John", "Adams"), ("Alice", "Brown")]
# Sort by first name (ascending), then by last name (descending)
sorted_names = sorted(names, key=lambda x: (ord(x[0][0]), -ord(x[1][0])))
print("Sorted by first char of first name, then reverse by first char of last name:")
for name in sorted_names:
print(f"{name[0]} {name[1]}")
# Alice Johnson
# Alice Brown
# John Smith
# John Adams
# Environment variables
import os
# Get environment variable with default
home = os.getenv('HOME', '/default/home')
print(f"Home directory: {home}")
# Set environment variable
os.environ['MY_VAR'] = 'Hello World'
print(os.environ.get('MY_VAR'))
# File system operations
import os
# Check if path exists
if os.path.exists('.'):
print("Current directory exists")
# List directory contents
try:
files = os.listdir('.')
print(f"Files in current dir: {len(files)}")
except PermissionError:
print("Permission denied")
Sys Module
# System information
import sys
print(f"Python version: {sys.version}")
print(f"Platform: {sys.platform}")
print(f"Max integer: {sys.maxsize}")
print(f"Python path: {sys.path[0]}")
# Command line arguments
import sys
print(f"Script name: {sys.argv[0] if sys.argv else 'N/A'}")
print(f"Arguments: {sys.argv[1:] if len(sys.argv) > 1 else 'None'}")
# Exit with status code
# sys.exit(0) # Uncomment to exit
# JSON serialization and deserialization
import json
data = {'name': 'Alice', 'age': 30, 'hobbies': ['reading', 'coding']}
json_str = json.dumps(data, indent=2)
print(json_str)
parsed_data = json.loads(json_str)
print(parsed_data['name']) # Alice
# JSON with custom encoder
import json
from datetime import datetime
class DateTimeEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime):
return obj.isoformat()
return super().default(obj)
data = {'timestamp': datetime.now(), 'message': 'Hello'}
json_str = json.dumps(data, cls=DateTimeEncoder)
print(json_str)
File Operations
# Basic file operations with context manager
with open('temp.txt', 'w') as f:
f.write('Hello World\n')
f.write('Python is awesome!')
with open('temp.txt', 'r') as f:
content = f.read()
print(content)
# Reading file line by line
with open('temp.txt', 'w') as f:
f.write('Line 1\nLine 2\nLine 3')
with open('temp.txt', 'r') as f:
for i, line in enumerate(f, 1):
print(f"Line {i}: {line.strip()}")
# File operations with error handling
try:
with open('nonexistent.txt', 'r') as f:
content = f.read()
except FileNotFoundError:
print("File not found!")
except PermissionError:
print("Permission denied!")
finally:
print("File operation completed")
Random Module
# Random numbers and choices
import random
print(random.randint(1, 10)) # Random integer between 1-10
print(random.random()) # Random float between 0-1
print(random.uniform(1.5, 10.5)) # Random float in range
colors = ['red', 'green', 'blue']
print(random.choice(colors)) # Random choice from list
# Random sampling and shuffling
import random
numbers = list(range(1, 11))
sample = random.sample(numbers, 3)
print(f"Sample: {sample}")
random.shuffle(numbers)
print(f"Shuffled: {numbers[:5]}") # First 5 elements
# Random with seed for reproducibility
import random
random.seed(42)
print(random.randint(1, 100)) # Always same result with seed 42
# Generate random string
import string
random_str = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
print(f"Random string: {random_str}")
Enums
# Basic enum usage
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED) # Color.RED
print(Color.RED.name) # RED
print(Color.RED.value) # 1
print(Color(2)) # Color.GREEN
def enum_type_func(input: Color) -> str:
"""the input type is not a plain, unspecific str or int, but a specifically enumerated type"""
if isinstance(input, Color):
return f"Valid color: {input.name}"
return "Invalid input"
# String enums and auto values
from enum import Enum, auto
class Status(Enum):
PENDING = "pending"
APPROVED = "approved"
REJECTED = "rejected"
class Priority(Enum):
LOW = auto()
MEDIUM = auto()
HIGH = auto()
print(Status.PENDING.value) # pending
print(Priority.HIGH.value) # 3
# Functional enum and iteration
from enum import Enum
# Functional API
Animal = Enum('Animal', 'CAT DOG BIRD')
print(Animal.CAT) # Animal.CAT
# Iterating through enum members
class Day(Enum):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
for day in Day:
print(f"{day.name}: {day.value}")
Type Conversions
# Basic type conversions
# String to other types
num_str = "42"
print(int(num_str)) # 42
print(float(num_str)) # 42.0
print(list(num_str)) # ['4', '2']
# Number to string
number = 123
print(str(number)) # "123"
print(f"{number}") # "123" (f-string)
# Advanced conversions with error handling
def safe_convert(value, target_type):
try:
return target_type(value)
except (ValueError, TypeError) as e:
return f"Conversion failed: {e}"
print(safe_convert("123", int)) # 123
print(safe_convert("abc", int)) # Conversion failed: invalid literal...
print(safe_convert([1,2,3], str)) # [1, 2, 3]
# Join list to string
words = ["hello", "world", "python"]
print(" ".join(words)) # hello world python
Mutable vs Immutable
# Dangerous default mutable argument
def bad_append(item, target_list=[]): # DON'T DO THIS!
target_list.append(item)
return target_list
print(bad_append(1)) # [1]
print(bad_append(2)) # [1, 2] - Unexpected!
print(bad_append(3)) # [1, 2, 3] - Still growing!
# Correct way with None default
def good_append(item, target_list=None):
if target_list is None:
target_list = []
target_list.append(item)
return target_list
# Immutable types cannot be modified in place
# Strings are immutable
text = "hello"
original_id = id(text)
text += " world" # Creates new string object
print(f"ID changed: {id(text) != original_id}") # True
# Tuples are immutable
coords = (1, 2)
# coords[0] = 3 # This would raise TypeError
# But tuple with mutable elements
nested = ([1, 2], [3, 4])
nested[0].append(3) # This works - modifying list inside tuple
print(nested) # ([1, 2, 3], [3, 4])
# Pytest exception testing
import pytest
def divide(a, b):
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
def test_divide_by_zero():
with pytest.raises(ValueError, match="Cannot divide by zero"):
divide(10, 0)
Unittest Examples
# Basic unittest class
import unittest
class Calculator:
def add(self, a, b):
return a + b
class TestCalculator(unittest.TestCase):
def setUp(self):
self.calc = Calculator()
def test_add(self):
self.assertEqual(self.calc.add(2, 3), 5)
self.assertNotEqual(self.calc.add(2, 3), 6)
# Run the tests
test = TestCalculator()
test.setUp()
test.test_add()
print("All tests passed!")
# Unittest assertions and mocking
import unittest
from unittest.mock import patch, MagicMock
class TestWithMock(unittest.TestCase):
def test_with_mock(self):
mock_obj = MagicMock()
mock_obj.method.return_value = 42
result = mock_obj.method()
self.assertEqual(result, 42)
mock_obj.method.assert_called_once()
# Run the tests
test = TestWithMock()
test.test_with_mock()
print("All tests passed!")
# Unittest with setUp and tearDown
import unittest
class TestLifecycle(unittest.TestCase):
def setUp(self):
self.data = [1, 2, 3]
def tearDown(self):
self.data.clear()
def test_data_length(self):
self.assertEqual(len(self.data), 3)
def test_data_content(self):
self.assertIn(2, self.data)
# Run the tests
test = TestLifecycle()
test.setUp()
test.test_data_length()
test.test_data_content()
test.tearDown()
print("All tests passed!")
Exception Handling
# Basic try/except/finally
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
else:
print("No exceptions occurred")
finally:
print("This always runs")
# Multiple exception types
try:
data = {"key": "value"}
result = data["missing_key"]
number = int("not_a_number")
except (KeyError, ValueError) as e:
print(f"Expected error: {e}")
except Exception as e:
print(f"Unexpected: {e}")
# Raising custom exceptions
class CustomError(Exception):
pass
def validate_age(age):
if age < 0:
raise CustomError("Age cannot be negative")
return age
try:
validate_age(-5)
except CustomError as e:
print(f"Validation error: {e}")
Classes and Objects
# Basic class with inheritance
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
pass
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
dog = Dog("Buddy")
print(dog.speak()) # Buddy says Woof!
# Class with properties and methods
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError("Radius must be positive")
self._radius = value
@property
def area(self):
return 3.14159 * self._radius ** 2
circle = Circle(5)
print(f"Area: {circle.area:.2f}") # Area: 78.54
# Class methods and static methods
class MathUtils:
pi = 3.14159
@classmethod
def circle_area(cls, radius):
return cls.pi * radius ** 2
@staticmethod
def add(a, b):
return a + b
print(MathUtils.circle_area(3)) # 28.27
print(MathUtils.add(5, 7)) # 12
# Lambda in comprehensions
numbers = [1, 2, 3, 4, 5]
operations = [lambda x, n=n: x * n for n in range(1, 4)]
results = [op(5) for op in operations]
print(results) # [5, 10, 15]
# Short-circuit evaluation
x = None
result = x and x.upper() # Won't raise AttributeError
print(result) # None
y = "hello"
result = y and y.upper() # Will execute y.upper()
print(result) # HELLO
# Boolean operators with non-boolean values
a = [] or [1, 2, 3] # [1, 2, 3]
b = "hello" and "world" # "world"
c = 0 or 5 or 10 # 5
d = "test" and [] or "fallback" # "fallback"
print(a, b, c, d)
Variable Scope
# Global and nonlocal keywords
count = 0 # Global
def outer():
count = 10 # Local to outer
def inner():
nonlocal count
count += 1
print(f"Inner count: {count}")
inner()
return count
print(f"Outer result: {outer()}") # 11
print(f"Global count: {count}") # 0
# Different import styles
import math
from math import sqrt, pi
from collections import Counter as C
import json as js
print(math.sqrt(16)) # 4.0
print(sqrt(25)) # 5.0
print(pi) # 3.141592653589793
counter = C([1, 1, 2, 3])
print(counter) # Counter({1: 2, 2: 1, 3: 1})
# Assignment expressions
numbers = [1, 2, 3, 4, 5]
if (n := len(numbers)) > 3:
print(f"List has {n} items")
# In while loop
data = [1, 2, 3, 4, 5]
while (item := data.pop() if data else None) is not None:
print(f"Processing: {item}")
if item == 2:
break
# Walrus in list comprehension
data = ['hello', 'world', 'python', 'code']
long_words = [(word, length) for word in data if (length := len(word)) > 4]
print(long_words) # [('hello', 5), ('world', 5), ('python', 6)]
# Walrus with regex
import re
text = "Phone: 123-456-7890"
if (match := re.search(r'\d{3}-\d{3}-\d{4}', text)):
print(f"Found phone: {match.group()}")
Match Statement (Python 3.10+)
# Pattern matching
def handle_data(data):
match data:
case int() if data > 0:
return f"Positive integer: {data}"
case str() if len(data) > 0:
return f"Non-empty string: {data}"
case []:
return "Empty list"
case [x] if isinstance(x, int):
return f"List with one integer: {x}"
case _:
return "Unknown data type"
print(handle_data(42)) # Positive integer: 42
print(handle_data("hello")) # Non-empty string: hello
print(handle_data([])) # Empty list
# Complex pattern matching
def process_point(point):
match point:
case (0, 0):
return "Origin"
case (0, y):
return f"On Y-axis at {y}"
case (x, 0):
return f"On X-axis at {x}"
case (x, y) if x == y:
return f"On diagonal at ({x}, {y})"
case (x, y):
return f"Point at ({x}, {y})"
print(process_point((0, 0))) # Origin
print(process_point((3, 3))) # On diagonal at (3, 3)
print(process_point((1, 2))) # Point at (1, 2)
F-string Advanced Formatting
# Advanced f-string formatting
name = "Alice"
score = 87.6789
width = 10
print(f"{name:>10}") # Right align: ' Alice'
print(f"{name:<10}") # Left align: 'Alice '
print(f"{name:^10}") # Center align: ' Alice '
print(f"{score:.2f}") # 87.68
print(f"{score:0{width}.2f}") # 0000087.68
# F-string with expressions and formatting
numbers = [1234567, 9876543]
for num in numbers:
print(f"{num:,}") # Thousands separator
print(f"{num:_}") # Underscore separator
print(f"{num:>15,}") # Right align with commas
percentage = 0.847
print(f"{percentage:.1%}") # 84.7%
print(f"{percentage:.2%}") # 84.70%
# F-string with conditional expressions
debug = True
name = "Alice"
score = 95
print(f"{'Debug:' if debug else ''} {name} scored {score}")
print(f"{name} {'passed' if score >= 60 else 'failed'}")
# F-string with datetime
from datetime import datetime
now = datetime.now()
print(f"Current time: {now:%Y-%m-%d %H:%M:%S}")
print(f"Date: {now:%B %d, %Y}")
Chained Comparisons
# Multiple comparisons
x = 5
if 0 < x < 10:
print("x is between 0 and 10")
age = 25
if 18 <= age < 65:
print("Working age")
# Chained equality
a = b = c = [1, 2, 3] # All reference same list
if a is b is c:
print("All variables reference the same object")
# Complex chained comparisons
score = 85
if 80 <= score < 90:
grade = 'B'
elif 90 <= score <= 100:
grade = 'A'
else:
grade = 'C'
print(f"Score {score} is grade {grade}")
# Multiple conditions
temperature = 72
humidity = 45
if 68 <= temperature <= 78 and 30 <= humidity <= 50:
print("Ideal conditions")
Generators
# Generator function
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Get first 10 fibonacci numbers
fib = fibonacci()
first_10 = [next(fib) for _ in range(10)]
print(first_10) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# Generator with yield from
def count_up_to(max_count):
count = 1
while count <= max_count:
yield count
count += 1
def count_and_repeat(max_count, repeat_times):
for _ in range(repeat_times):
yield from count_up_to(max_count)
result = list(count_and_repeat(3, 2))
print(result) # [1, 2, 3, 1, 2, 3]
Assertions
# Basic assertions
def divide(a, b):
assert b != 0, "Division by zero is not allowed"
return a / b
result = divide(10, 2)
print(result) # 5.0
# This would raise AssertionError
# divide(10, 0)
# Assertions for debugging
def process_list(items):
assert isinstance(items, list), "Input must be a list"
assert len(items) > 0, "List cannot be empty"
result = []
for item in items:
assert isinstance(item, (int, float)), f"Item {item} must be a number"
result.append(item * 2)
return result
numbers = [1, 2, 3, 4]
doubled = process_list(numbers)
print(doubled) # [2, 4, 6, 8]
Dynamic Function Execution
# Global Namespace Function Execution
def run_functions(function_list):
function_name = function_list[0]
args = function_list[1:]
if function_name in globals():
return globals()[function_name](*args)
else: # 'riskier' alternative way
# be careful with exposing an eval() function that can run anything to a user
function = eval(function_name)
return function(*args)
# Built-in and custom functions
def add(a, b):
return a + b
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
# Execute various functions
operations = [
['len', 'hello world'],
['max', 5, 3, 8, 1],
['add', 10, 5],
['greet', 'Alice', 'Hi']
]
for op in operations:
result = run_functions(op)
print(f"{op[0]}{tuple(op[1:])} = {result}")
# len('hello world',) = 11
# max(5, 3, 8, 1) = 8
# add(10, 5) = 15
# greet('Alice', 'Hi') = Hi, Alice!