RUNTIME VALUE CONVERSIONS

Functions, annotations, and closures

Pass supported values and callables between functions, declare the types that your boundaries accept, and capture local variables with nested functions or lambdas.

Function parameters and returns

Runtime functions accept positional and keyword arguments, defaults, positional-only parameters before /, keyword-only parameters, and variadic parameters. *args collects extra positional values into a tuple; **kwargs collects extra keywords into an ordered dictionary. Parameter and return annotations are optional. Returning a mutable value preserves its shared identity.

The same binding rules apply to top-level and nested functions, lambdas, constructors, and bound methods. Missing required arguments, duplicate values, and unexpected keywords report errors. A positional-only name may also appear as an independent key in **kwargs. Typed conversion has separate required keyword-call forms.

Calls accept *iterable and **dictionary, including multiple expansions mixed with ordinary arguments. Dictionary keys must be strings without embedded NUL characters; duplicate keywords report an error. The callee is evaluated first, followed by positional expressions and then keyword expressions. A sole *iterable remains live until keyword evaluation finishes; mixed positional expansions are consumed in sequence.

def label(name: str, /, count: int = 1, *, suffix: str = "!") -> str:
    return f"{name.strip()}: {count}{suffix}"

def main() -> int:
    print(label(" jobs ", suffix=".", count=3))
    print(label("items"))
    return 0

This prints jobs: 3. and items: 1!. The name is positional-only; the suffix is keyword-only.

When defaults are created

Default expressions are evaluated once, from left to right, when each function or lambda is defined. Repeated calls reuse the same stored value. A mutable list or dictionary default is therefore shared; use a None default and create a list inside the function when each call needs its own list.

Each execution of a nested definition creates a new function with its own defaults. Captured variables remain shared with that function's enclosing scope.

def remember(value: int, history: list[int] = []) -> int:
    history.append(value)
    return len(history)

def main() -> int:
    print(remember(4), remember(value=7), remember(9, history=[]))
    return 0

This prints 1 2 1. Module function and method defaults are initialized in source order once per C context, before its first public function call. They may use supported expressions and earlier module definitions; referencing a later definition at that point reports a name error.

Create fresh data for each call

def remember(value: int, history: list[int] | None = None) -> int:
    if history is None:
        history = []
    history.append(value)
    return len(history)

def main() -> int:
    print(remember(4), remember(7))
    return 0

This prints 1 1. Each omitted history creates a separate list. Passing an existing list deliberately still shares that list.

Supported annotations

AnnotationAccepted value
bool, int, float, str, NoneThe corresponding runtime kind. Integer checks also admit Boolean values; float checks require floating values.
A declared class nameAn instance of that class or any of its declared subclasses.
int | str, Counter | NoneA value accepted by either annotation.
list, tuple, dict, set, frozensetThe named container kind without an element constraint.
dict[K, V]A dictionary whose current keys satisfy K and values satisfy V.
list[T], set[T], frozenset[T]The named container kind whose current elements satisfy T.
tuple[T, U]A fixed-length tuple with separately checked positions.
tuple[T, ...]A tuple of any admitted length whose elements satisfy T.
objectAny initialized supported value, including a callable.

Use annotation names directly. Imports from typing, quoted forward annotations, and general annotation expressions are unsupported.

def choose(ready: bool) -> int | str:
    result: int | str
    if ready:
        result = 4
    else:
        result = "waiting"
    return result

choose(True) returns 4; choose(False) returns "waiting".

Function and assignment checks

Annotations check arguments on entry, returned values, stores to annotated local names, and stores to declared fields. An annotation without an initial value leaves the local uninitialized. Every executed read still needs an earlier assignment.

An annotation on *args checks each extra argument; an annotation on **kwargs checks each extra keyword value. Stores through nonlocal retain the enclosing binding's annotation checks.

Checks do not coerce values: use 1.0 or float(value) when a float is required. An unannotated binding may change type; an annotated binding must continue to satisfy its declared annotation. Redeclaring a name with an incompatible annotation is rejected.

Container checks inspect elements at the boundary being crossed. They do not permanently bind a type schema to every alias. For example, appending text through an unannotated alias of a list does not itself enforce an earlier list[int] declaration; passing that list to an annotated list[int] parameter then fails. This checking is part of the C conversion contract; Python itself does not enforce ordinary annotations at runtime.

Pass and decorate functions

def increment_result(operation):
    def wrapper(value: int) -> int:
        return operation(value) + 1
    return wrapper

@increment_result
def calculate(value: int) -> int:
    return value

calculate(4) returns 5. The decorator receives the original function and returns its replacement. Functions, lambdas, and bound methods can also be passed directly as arguments, returned, or stored in containers.

Top-level functions, nested functions, and ordinary methods accept decorators and decorator factories. Decorator expressions run from top to bottom before defaults are evaluated; their results are applied from bottom to top. The name is bound only after all applications finish. Wrappers can forward *args and **kwargs and retain shared state. Each wrapped function keeps its own argument and annotation checks.

Decorators use the same supported operations as other functions, including explicitly supplied modules. Class decorators, static/class methods, properties, function metadata attributes, and implicit standard-library imports such as functools are unsupported.

Functions and captured variables

def make_offset(start: int):
    offset = start
    def transform(value):
        nonlocal offset
        offset += 1
        return value + offset
    return transform

def calculate(value: int) -> int:
    transform = make_offset(3)
    return transform(value)

calculate(10) returns 14. The nested function changes the enclosing offset through nonlocal. Without that declaration, assigning the same name creates a separate local binding. Captured storage survives the creating function and remains valid for the C context's lifetime.

Nested functions support recursion and calls between sibling functions once their definitions have executed. Lambdas use the same parameter forms with an expression body. Both can be returned, passed to other functions, or stored in containers; distinct creations have distinct identity. Deleting a local or nonlocal name makes it uninitialized until assigned again. Nested classes and mutable module-global bindings are unsupported.

Late binding in a comprehension

def main() -> int:
    operations = [lambda value: value + offset for offset in range(3)]
    print(operations[0](10), operations[2](10))
    return 0

Both calls print 12: the lambdas share the comprehension variable, whose final value is 2. A default parameter captures the current value when each lambda is created:

def main() -> int:
    operations = [lambda value, offset=offset: value + offset
                  for offset in range(3)]
    print(operations[0](10), operations[2](value=10))
    return 0

This prints 10 12. A captured mutable object is still shared; a default saves its reference, not a deep copy.

Call and capture limits

Functions have at most 64 decorators and 64 declared parameters, including variadic names; calls accept at most 64 supplied values after expansion. Functions have at most 1,024 local bindings; a closure can capture up to 256 local cells. Calls are checked against a depth limit of 128. Invalid arguments, incompatible annotations, uninitialized reads, and resource exhaustion report runtime errors. See C caller error handling.