Learning

Advanced Function Design

Advanced Function Design

Default Arguments

python
# 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 and **kwargs

python
# *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

Lambda Functions

python
# 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

Recursion

python
# 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)

Closures & LEGB Scope

python
# 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()) # 2
Key Rules
  • •NEVER use mutable default arguments (like []) — they are created once and shared across all calls
  • •Use None as default and initialize inside the function if you need a fresh mutable object
  • •*args collects extra positional args into a tuple, **kwargs collects extra keyword args into a dict
  • •Lambda is limited to a SINGLE expression — use def for anything complex
  • •Every recursive function MUST have a base case that stops recursion, otherwise it hits max depth
  • •Use 'nonlocal' keyword to modify a variable in the enclosing scope from inside a nested function
Your Task

Create 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).

EditorPython · JSX
PreviewUpdates on Run Tests
Loading preview…
Tests
Should define make_multiplier with nested function
Should define recursive power function
Power should have base case for exp==0
Should define merge_configs with *dicts
Should use .update() for merging
Should test with 3 dictionaries including override