# Default values are evaluated ONCE at definition time!
def greet(name, greeting='Hello'):
return f'{greeting}, {name}!'
print(greet('Alice')) # 'Hello, Alice!'
print(greet('Bob', 'Hey')) # 'Hey, Bob!'
# ⚠️ Mutable default argument BUG!
def add_item(item, lst=[]): # Dangerous!
lst.append(item)
return lst
print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] (shared across calls!)
# ✅ Correct way: use None
def add_item_safe(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst# *args → tuple of positional arguments
def sum_all(*args):
return sum(args)
print(sum_all(1, 2, 3)) # 6
# **kwargs → dict of keyword arguments
ndef print_info(**kwargs):
for key, val in kwargs.items():
print(f'{key}: {val}')
print_info(name='Alice', age=30)
# Mixing them (order matters!)
def func(a, b, *args, key='default', **kwargs):
pass# Anonymous single-expression functions
square = lambda x: x ** 2
add = lambda x, y: x + y
# Best used with map/filter/sorted
names = ['Charlie', 'Alice', 'Bob']
names.sort(key=lambda n: len(n)) # Sort by length
# Conditional lambda
is_adult = lambda age: True if age >= 18 else False# Factorial
def factorial(n):
if n <= 1: # Base case (MUST have!)
return 1
return n * factorial(n - 1) # Recursive case
# Fibonacci
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2) # Exponential time! (Use memoization for production)# LEGB: Local → Enclosing → Global → Built-in
x = 'global'
def outer():
x = 'enclosing'
def inner():
x = 'local'
print(x) # 'local'
inner()
# Closure: inner function remembers enclosing scope
def make_counter():
count = 0
def counter():
nonlocal count # Required to modify enclosing var!
count += 1
return count
return counter
c = make_counter()
print(c()) # 1
print(c()) # 2Create a closure `make_multiplier(factor)` that returns a function multiplying by `factor`. Create a recursive function `power(base, exp)` that calculates base^exp without using `**` or `math.pow`. Create a function `merge_configs(*dicts)` that accepts any number of dictionaries and merges them into one (later dicts override earlier ones).