def

def builds a function object and binds it to a name. Defaults are evaluated once, at definition time — the source of Python’s most famous trap.

FunctionsPython 3 (all)Live demo
def
def name(a, b):
    body
    return value
defaults
def name(a, b=10):
    ...
*args / **kwargs
def name(*args, **kwargs):
    ...
/ and * markers
def name(a, /, b, *, c):
    ...
Use for
Any reusable piece of logic that takes inputs and returns a result
Result
a statement — binds a function object to the name
Pairs with
return, lambda, yield, @decorators, *args, **kwargs
Watch out
default values are created once, not per call — never use [] or {} as a default

Demo

Live evaluation
low and high have defaults. Pass high by keyword and leave low alone.
Try:
Inputs
xintvalue to clamp
highintupper bound
Code
def clamp(x, low=0, high=10):
    return max(low, min(x, high))
(clamp(7), clamp(7, high=5))
Result
(7, 5)

In the mutable default tab, a and b are the same list object (a is b is True) — the second call appended to the list the first call returned. In the *args tab, an empty list leaves nothing for the required first parameter, so the call fails before the body runs.

Syntax slots

NameTypeRequiredDescription
namenameyesThe variable the new function object is bound to. Rebinding it later replaces the function.
parametersparameter listnoPlain names, name=default, *args (extra positionals as a tuple), **kwargs (extra keywords as a dict). / ends positional-only, a bare * starts keyword-only.
defaultexpressionnoEvaluated ONCE when def runs, and the same object is reused by every call that omits the argument.
bodyblockyesRuns on each call. Ends at return (or falls off the end, which returns None).

Common patterns

None as the "no value" default
The safe replacement for a mutable default.
def add(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket
Keyword-only options
Everything after * must be passed by name, so call sites stay readable.
def connect(host, port, *, timeout=5, retries=3):
    ...
Forwarding arguments
A wrapper that passes everything through unchanged.
def logged(func):
    def wrapper(*args, **kwargs):
        print("calling", func.__name__)
        return func(*args, **kwargs)
    return wrapper
Docstring first
A string literal as the first statement becomes func.__doc__ (shown by help()).
def area(w, h):
    """Return the area of a w x h rectangle."""
    return w * h

Examples

1. Define and call
def greet(name): return f'Hello, {name}!' greet('Ann')
Returns
'Hello, Ann!'
2. Default and keyword arguments
def power(base, exp=2): return base ** exp (power(3), power(2, exp=10))
Returns
(9, 1024)
3. *args and **kwargs
def f(*args, **kwargs): return args, kwargs f(1, 2, x=3)
Returns
((1, 2), {'x': 3})
4. Positional-only and keyword-only
def f(a, /, b, *, c): return a, b, c f(1, b=2, c=3)
Returns
(1, 2, 3)
5. Breaking the markers
def f(a, /, b, *, c): return a, b, c f(1, 2, 3)
Returns
TypeError: f() takes 2 positional arguments but 3 were given
6. Functions are objects
def square(x): return x * x ops = {'sq': square} (ops['sq'](4), square.__name__)
Returns
(16, 'square')
7. A decorator with @
def shout(func): def wrapper(*args): return func(*args).upper() return wrapper @shout def greet(name): return f'hi {name}' greet('bo')
Returns
'HI BO'

Pitfalls

1. A mutable default argument
The default list is created once when def runs and shared by every call that omits the argument.
bucket=[]
def add(item, bucket=[]):
    bucket.append(item)
    return bucket
add(1)
add(2)
[1, 2]
bucket=None
def add(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket
add(1)
add(2)
[2]
2. Forgetting return
A function that computes a value but never returns it gives back None.
no return
def double(x):
    x * 2
print(double(4))
None
return it
def double(x):
    return x * 2
print(double(4))
8
3. Referencing the function instead of calling it
Without parentheses you get the function object, which is never equal to its result.
no ()
def get():
    return 42
result = get
result == 42
False
call it
def get():
    return 42
result = get()
result == 42
True
4. A required parameter after a default
Once a parameter has a default, every positional parameter after it needs one too.
b after a=1
compile('def f(a=1, b): pass', '<demo>', 'exec')
SyntaxError: parameter without a default follows parameter with a default
required first
def f(b, a=1):
    return a, b
f(2)
(1, 2)

When to use

Use it
  • Logic you call from more than one place
  • Anything longer than one expression, or that needs statements, a docstring or a name in tracebacks
  • Giving a meaningful name to a step of a larger computation
Reach for something else
  • A tiny one-off key= or callback expression → lambda
  • A function that produces a series of values → still def, but with yield (a generator)
  • Several functions sharing state → a class may read better than closures

Notes

CPython impl
def is executed at runtime: it evaluates the defaults, builds a function object from pre-compiled code and binds it to the name
Defaults
Stored in func.__defaults__ (and __kwdefaults__ for keyword-only) — a mutated default is visible there
Scope
Names assigned inside the body are local unless declared global or nonlocal

FAQ

*args collects any extra positional arguments into a tuple, **kwargs collects any extra keyword arguments into a dict. The names are convention; the * and ** are what matter. At a call site, * and ** do the reverse: f(*items, **options) unpacks them into arguments.

History

3.8
The / function parameter syntax may be used to indicate positional-only parameters (PEP 570).
3.9
Functions may be decorated with any valid assignment expression.
3.12
Type parameter lists (def f[T](x: T)) are new.