Functions¶
Functions are first-class objects in Python - they can be passed as arguments, returned from other functions, and stored in variables. Understanding scope rules (LEGB), closures, and higher-order functions is essential for writing idiomatic Python.
Key Facts¶
defdefines a function; withoutreturn, function returnsNone- Parameter order:
def f(pos, *args, key=default, **kwargs) *argscollects extra positional args as tuple;**kwargsas dict- LEGB scope: Local, Enclosing, Global, Built-in
- Lambdas are single-expression anonymous functions
map()andfilter()return one-time iterators (exhausted after single pass)
Patterns¶
Function Definition¶
def greet(name, greeting="Hello"):
"""Greeting function with optional prefix."""
return f"{greeting}, {name}!"
greet("Alice") # "Hello, Alice!"
greet("Alice", "Hi") # "Hi, Alice!"
args and *kwargs¶
def my_func(*args, **kwargs):
for item in args: # tuple
print(item)
for key, val in kwargs.items(): # dict
print(f"{key}={val}")
my_func(1, 2, fruit='apple', color='red')
LEGB Scope¶
x = 25 # Global
def outer():
x = 50 # Enclosing
def inner():
x = 75 # Local
print(x) # 75
inner()
outer()
print(x) # 25 (global unchanged)
global and nonlocal¶
count = 0
def increment():
global count # modify module-level variable
count += 1
def counter():
n = 0
def inc():
nonlocal n # modify enclosing scope variable
n += 1
return n
return inc
Closures¶
def make_adder(n):
def add(x):
return x + n # n captured from enclosing scope
return add
plus_3 = make_adder(3)
plus_3(10) # 13
# Closure with mutable state
def counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
Lambda¶
square = lambda x: x ** 2
add = lambda a, b: a + b
classify = lambda x: 'even' if x % 2 == 0 else 'odd'
# Most useful inline
sorted(words, key=lambda w: len(w))
sorted(items, key=lambda x: x[1]) # sort by second element
map() and filter()¶
list(map(lambda x: x**2, [1, 2, 3])) # [1, 4, 9]
list(filter(lambda x: x % 2 == 0, range(10))) # [0, 2, 4, 6, 8]
list(filter(None, [0, '', None, 'hello'])) # ['hello'] (truthy filter)
# Multiple iterables
list(map(pow, [2, 3, 4], [4, 2, 3])) # [16, 9, 64]
operator Module (avoid trivial lambdas)¶
import operator
sorted(items, key=operator.itemgetter(1)) # vs lambda x: x[1]
sorted(objs, key=operator.attrgetter('name')) # vs lambda x: x.name
Multiple Return Values¶
def min_max(lst):
return min(lst), max(lst) # returns tuple
lo, hi = min_max([3, 1, 4, 1, 5]) # unpacking
Early Return¶
Functions as First-Class Objects¶
Docstrings¶
def my_func(param):
"""
Brief description.
Args:
param: description
Returns:
description of return value
"""
pass
# Access: my_func.__doc__ or help(my_func)
Built-in Functions Reference¶
| Category | Functions |
|---|---|
| Type conversion | int(), float(), str(), bool(), list(), tuple(), set(), dict() |
| Math | abs(), round(), divmod(), pow(), min(), max(), sum() |
| Iteration | len(), range(), enumerate(), zip(), sorted(), reversed(), all(), any() |
| Functional | map(), filter() |
| Introspection | type(), isinstance(), id(), dir(), help(), callable() |
| Base conversion | hex(), oct(), bin(), ord(), chr() |
Gotchas¶
- Never shadow built-in names:
list = [1, 2]breakslist()function map(square, nums)notmap(square(), nums)- pass function object without calling itmap()/filter()iterators are exhausted after one pass - convert to list if needed- Mutable default arguments are shared across calls: use
def f(x=None): x = x or [] - Without
return, function returnsNoneimplicitly
See Also¶
- decorators - wrapping functions
- iterators and generators - generator functions with yield
- oop fundamentals - methods vs functions