Positional vs keyword arguments

RoadmapsPython Backend

Overview

Python lets you enforce HOW arguments must be passed using two special markers in the signature: * (bare star) makes everything after it keyword-only — callers MUST name those arguments: def create_user(name, *, role='member', active=True): ... create_user('alice', role='admin') # ok create_user('alice', 'admin') # TypeError — role must be named / makes everything before it positional-only — callers CANNOT name those arguments: def build_path(base, endpoint, /): return base + endpoint build_path('/api', '/users') # ok build_path(base='/api', endpoint='/users') # TypeError Both can appear together: def f(pos_only, /, normal, *, kw_only). / requires Python 3.8+. Think of * as a 'name required from here on' wall, and / as a 'no naming allowed before this' wall.

Keyword-only parameters make call sites self-documenting (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: *args & **kwargs

Return to Python Backend Roadmap