Functions · Lesson 10 of 18 · 20 min
Functions and scope
Parameters, return, LEGB, and the default-argument trap.
- Define parameters: positional, keyword, defaults, *args, **kwargs
- Trace LEGB name lookup
- Avoid mutable default arguments
A function is an object you call
`def` is an assignment. It creates a function object and binds it to a name. That object carries the code, default values, and a reference to the defining environment. Because functions are objects, you can pass them, store them in lists, and return them.
Parameters have a strict order: positional-only (`/` in the signature), ordinary positional-or-keyword, variadic `*args`, keyword-only (after `*`), and `**kwargs`. You will not need all of these every day, but you will read them in the standard library.
def connect(host, port=5432, /, *, timeout=5, **opts):
return {"host": host, "port": port, "timeout": timeout, **opts}
print(connect("localhost"))
print(connect("localhost", 6432, timeout=1, ssl=True))
def gather(a, *rest):
return a, rest
print(gather(1, 2, 3))LEGB
Name lookup walks Local, Enclosing, Global, Built-in. Assignment without `global` or `nonlocal` always creates a local. That is why `count = count + 1` inside a function errors if you meant the module-level count: Python sees the assignment and treats `count` as local for the whole function.
`global name` rebinds a module name. `nonlocal name` rebinds a name in the nearest enclosing function. Use both rarely. Returning values and passing arguments is clearer than mutating outer state.
x = "global"
def outer():
x = "enclosing"
def inner():
return x
return inner()
print(outer())
def broken():
print(x)
# assigning x here would make the print above fail:
# Python would treat x as local for the whole function.
broken()def add_bad(item, bucket=[]):
bucket.append(item)
return bucket
print(add_bad(1))
print(add_bad(2))
def add_good(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket
print(add_good(1), add_good(2))Check yourself
Quiz
1.After `def f(a, b=1):`, a valid call is:
2.Why does `def f(xs=[]): xs.append(1); return xs` grow across calls?
3.LEGB stands for:
Practice
Exercise
Write `clamp(n, lo=0, hi=100)` that returns n limited to [lo, hi]. Write `first(*values, default=None)` that returns the first argument, or default if none were passed.
Tutor
Ask a question about this lesson. Answers are generated on demand and capped so the session stays focused.