def uppercase(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
@uppercase
def greet(name):
return f'hello {name}'
print(greet('alice')) # 'HELLO ALICE'def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for _ in range(n):
results.append(func(*args, **kwargs))
return results
return wrapper
return decorator
@repeat(3)
def say_hi():
return 'hi'
print(say_hi()) # ['hi', 'hi', 'hi']import functools
def timer(func):
@functools.wraps(func) # Preserves metadata!
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
print(f'{func.__name__} took {time.time()-start:.4f}s')
return result
return wrapper
@timer
def slow_function():
"""A slow function"""
import time
time.sleep(0.1)
print(slow_function.__name__) # 'slow_function' (not 'wrapper')
print(slow_function.__doc__) # 'A slow function'class CountCalls:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f'Call #{self.count}')
return self.func(*args, **kwargs)
@CountCalls
def add(a, b):
return a + b
print(add(1, 2)) # Call #1, then 3
print(add(3, 4)) # Call #2, then 7
print(add.count) # 2def bold(func):
def wrapper(*args, **kwargs):
return f'**{func(*args, **kwargs)}**'
return wrapper
def italic(func):
def wrapper(*args, **kwargs):
return f'_{func(*args, **kwargs)}_'
return wrapper
@bold
@italic # Applied first (bottom-up!)
def text():
return 'hello'
print(text()) # '**_hello_**'def retry(max_attempts=3):
def decorator(func):
import functools
@functools.wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts:
raise
print(f'Attempt {attempt} failed: {e}')
return wrapper
return decoratorCreate: 1) `@timer` decorator that prints execution time using `time.perf_counter()`. 2) `@validate_types(*expected_types)` decorator factory that checks argument types match expected. 3) `@CountCalls` class-based decorator that counts calls and prints count. Apply `@CountCalls` then `@timer` to a `factorial(n)` function. Demonstrate with valid and invalid type calls.