Master advanced Python concepts: decorators, generators, and modular programming.
Learn powerful Python features used by professional developers.
# A decorator is a function that takes a function
# and returns a modified version of that function
# Without decorator syntax:
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello) # Manual decoration# The @ symbol is syntactic sugar for decoration
@my_decorator
def say_hello():
print("Hello!")
# This is equivalent to: say_hello = my_decorator(say_hello)import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end-start:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
print("Done!")
• *args, **kwargs allows the wrapper to accept any argumentsdef repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def greet(name):
print(f"Hello, {name}!")@functools.wraps(func) to preserve function metadata@decorator1 @decorator2self passed through *argsBefore function call
Hello, World!
After function call
greet took 0.0001 seconds
Hello, Alice!
Hello, Alice!
Hello, Alice!
def decorator(func): def wrapper(): ... return wrapper@decorator above function definitiondef wrapper(*args, **kwargs):result = func(*args, **kwargs)return wrapper from decoratorreturn result from wrapperReview feedback below
yield keyword instead of return.# List: stores ALL values in memory at once
numbers_list = [x ** 2 for x in range(1000000)] # Uses lots of memory!
# Generator: generates values ONE AT A TIME
numbers_gen = (x ** 2 for x in range(1000000)) # Uses minimal memory!def count_up_to(n):
"""Generate numbers from 1 to n"""
i = 1
while i <= n:
yield i # Pause here, return i, resume on next call
i += 1
# Usage:
for num in count_up_to(5):
print(num) # Prints 1, 2, 3, 4, 5
• yield pauses the function and returns a valuedef fibonacci(limit):
"""Generate Fibonacci numbers up to limit"""
a, b = 0, 1
while a < limit:
yield a
a, b = b, a + b
# Usage:
for fib in fibonacci(100):
print(fib) # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89gen = count_up_to(3)
print(next(gen)) # 1
print(next(gen)) # 2
print(next(gen)) # 3
# print(next(gen)) # StopIteration error!# Use parentheses instead of brackets
squares_gen = (x**2 for x in range(10))
# Convert to list if needed
squares_list = list(squares_gen)yield from to delegate to another generatorsend() can pass values into a generator1
2
3
4
5
Fibonacci: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
First 5 squares: [0, 1, 4, 9, 16]
def gen(): yield value(x for x in range(10))for item in generator:next(generator)list(generator)Review feedback below
import math
import random
import datetime
# Use with module prefix
print(math.pi) # 3.141592653589793
print(math.sqrt(16)) # 4.0
print(random.randint(1, 10)) # Random number 1-10from math import pi, sqrt, ceil, floor
from random import choice, shuffle
# Use directly without prefix
print(pi) # 3.141592653589793
print(sqrt(25)) # 5.0
print(choice(['a', 'b', 'c'])) # Random elementimport datetime as dt
from collections import Counter as C
now = dt.datetime.now()
print(now.strftime("%Y-%m-%d %H:%M"))
word_counts = C("hello world".split())
print(word_counts) # Counter({'hello': 1, 'world': 1})# os - Operating system interface
import os
print(os.getcwd()) # Current directory
# json - JSON encoding/decoding
import json
data = {"name": "Alice", "age": 30}
json_str = json.dumps(data)
print(json_str) # '{"name": "Alice", "age": 30}'
# collections - Specialized containers
from collections import defaultdict, namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(3, 4)
print(p.x, p.y) # 3 4import math
print(dir(math)) # List all attributes
help(math.sqrt) # Get help on a functionif __name__ == "__main__": for script entry pointsfrom module import * (pollutes namespace)pip install package_name for third-party packagesPi: 3.141592653589793
Square root of 16: 4.0
Random number: 7
Current time: 2024-01-15 10:30:45
JSON: {"name": "Alice", "age": 30}
import math then math.sqrt()from math import sqrt, piimport datetime as dtdir(module) lists contentshelp(math.sqrt) shows documentationReview feedback below