Keyword-only and positional-only parameters

RoadmapsPython

Overview

Python lets you enforce HOW arguments must be passed using two special markers in the signature. The `*` (bare star) makes everything after it keyword-only, meaning callers MUST name those arguments. It acts as a "name required from here on" wall. def create_user(name, *, role='member', active=True): pass create_user('alice', role='admin') # ok create_user('alice', 'admin') # TypeError The `/` (forward slash) makes everything before it positional-only, meaning callers CANNOT name those arguments. It acts as a "no naming allowed before this" wall. def build_path(base, endpoint, /): return base + endpoint build_path('/api', '/users') # ok build_path(base='/api', endpoint='/users') # TypeError Both markers can appear together in the same function signature. The `/` marker requires Python 3.8+. def f(pos_only, /, normal, *, kw_only): pass def delete_record(record_id, *, confirm): pass delete_record(42) # TypeError: missing 1 required keyword-only argument: 'confirm' Keyword-only parameters without default values become strictly required. Callers are forced to explicitly name them, which is perfect for dangerous operations or boolean flags. def invalid_order(a, *, b, c, /): pass # SyntaxError: positional-only argument follows keyword-only argument The parameter order is strictly enforced by Python. Positional-only parameters (and `/`) must appear before regular parameters, which must appear before the keyword-only marker (`*`).

Keyword-only parameters make call sites self-documenting (e.g., `create_user('alice', role='admin')` is clearer than `create_user('alice', 'admin')`) and prevent callers from passing booleans in the wrong order. Positional-only parameters let library authors rename internal parameters without breaking callers.

Where used: FastAPI `Depends()` uses keyword-only injection, Python stdlib (`sorted(key=..., reverse=...)`), Pydantic model constructors

Why learn this

Code walkthrough

def resize(width, height, /, *, quality='high'):
    print(f'{width}x{height} at {quality}')

resize(1920, 1080)
resize(1280, 720, quality='low')

Focus: `width` and `height` are positional-only (before `/`); `quality` is keyword-only (after `*`) — the call site must name `quality` but cannot name `width` or `height`.

Common mistakes

Glossary

signature
The definition of a function that shows its name and exactly what arguments it expects to receive. Example: `def add(a, b):`.
call sites
The specific places in your code where a function is actually executed or invoked. Example: `result = my_func(5)` is a call site.
keyword argument
Passing a value to a function by explicitly writing the parameter's name (the keyword), followed by an equals sign, and then the value. Example: `role='admin'`.
positional argument
Passing a value to a function purely based on its order in the list, without writing any parameter name. Example: in `create_user('alice')`, `'alice'` is a positional argument because it's first.
keyword-only
A parameter that MUST be passed as a keyword argument, meaning you are forced to type out its name. Example: `def f(*, kw_only=True):`.
positional-only
A parameter that MUST be passed as a positional argument, meaning you are forbidden from typing out its name. Example: `def f(pos_only, /):`.
TypeError
An error that Python throws when an operation or function is applied to an object of inappropriate type, or when function arguments don't match the signature. Example: `len(5)` raises a `TypeError`.

Recall questions

Understanding checks

What is the output of this code?

localhost:8080 (False)

`host` is positional-only (passed as "localhost"), `port` can be passed normally (passed as a keyword argument here), and `secure` has a default value, so it doesn't need to be provided.

Why does this function call raise a `TypeError`?

Because `url` is a positional-only parameter, but it is being passed as a keyword argument.

The `/` in the signature enforces that all parameters before it (like `url`) must be passed purely by their position, not by name.

Practice tasks

Refactor to Enforce Keyword and Positional Arguments

The function below currently allows any argument to be passed positionally or by name. Modify the function signature so that `user_id` and `message` MUST be passed positionally, and `dry_run` and `urgent` MUST be passed by keyword.

Challenge

Safe cache setter

Write `set_cache(key, value, /, *, ttl=60, overwrite=False)` where `key` and `value` are positional-only (internal names may change) and `ttl` and `overwrite` are keyword-only flags. Print a summary line for each call. Demonstrate three calls: default, custom `ttl`, and `overwrite=True`.

Continue learning

Previous: Defining functions and return values

Previous: *args and **kwargs

Return to Python Roadmap