Note *args collects extra positional arguments as a tuple, **kwargs collects extra keyword arguments as a dict. They can coexist in the same signature.
GET https://api.example.com (timeout=10, retries=3)
Note / marks preceding params as positional-only. * marks following params as keyword-only. This prevents callers from relying on internal parameter names.
keyword onlypositional onlyslash in functionenforce keyword
Lambda (Anonymous Functions)
Syntax
lambda params: expression
Example
square =lambda n: n **2print(square(5))
users =[{"name":"Carol","age":28},{"name":"Alice","age":35}]
users.sort(key=lambda u: u["age"])print([u["name"]for u in users])
Output
25
['Carol', 'Alice']
Note Lambdas are limited to a single expression. For anything with statements or multiple lines, use a regular def. Assigning a lambda to a variable is less readable than def.
lambdaanonymous functioninline functionsort key function
Decorators
Syntax
@decorator
deffunc():...
Example
import functools
import time
deftimer(func):
@functools.wraps(func)defwrapper(*args,**kwargs):
start = time.perf_counter()
result =func(*args,**kwargs)
elapsed = time.perf_counter()- start
print(f"{func.__name__} took {elapsed:.4f}s")return result
return wrapper
@timer
defcompute(n):returnsum(range(n))compute(1_000_000)
Output
compute took 0.0XXXs
Note Always use @functools.wraps(func) in your wrapper so that the decorated function preserves its name and docstring. Decorators run at import time.
defouter():
captured = value
definner():return captured
return inner
Example
defmake_multiplier(factor:int):defmultiply(n:int)->int:return n * factor
return multiply
double =make_multiplier(2)
triple =make_multiplier(3)print(double(10),triple(10))
Output
20 30
Note The inner function captures the enclosing variable by reference, not by value. See Common Mistakes for the late-binding closure gotcha.
closurefunction factorycaptured variableinner function
Generators with yield
Syntax
defgen():yield value
Example
defcountdown(n:int):while n >0:yield n
n -=1for tick incountdown(3):print(tick)# Generators are lazy - values produced one at a time
nums =countdown(1_000_000)print(next(nums))
Output
3
2
1
1000000
Note Generators produce values lazily, consuming almost no memory regardless of size. They are single-use: once exhausted, they cannot be restarted.
from collections.abcimportCallabledefapply(
values:list[int],
transform:Callable[[int],int])->list[int]:return[transform(v)for v in values]
result =apply([1,2,3],lambda x: x *10)print(result)
Output
[10, 20, 30]
Note Use collections.abc.Callable for function type hints. The format is Callable[[ArgTypes], ReturnType]. For complex signatures, consider typing.Protocol.
deffunc(n):if base_case:return value
returnfunc(modified_n)
Example
deffactorial(n:int)->int:if n <=1:return1return n *factorial(n -1)print(factorial(6))import sys
print(f"Recursion limit: {sys.getrecursionlimit()}")
Output
720
Recursion limit: 1000
Note Python's default recursion limit is 1000. Deeply recursive algorithms should be rewritten iteratively or use sys.setrecursionlimit() with caution.