"Python Keyword-Only Arguments: What Bare * Does"
"Python keyword-only arguments are parameters a caller must pass by name. A bare * in the signature draws the line: everything after it is keyword-only. This quick answer shows one runnable example, three common variations, the gotchas that bite, and answers to the questions everyone asks."
Python keyword-only arguments are parameters that must be passed by name, never positionally. Put a bare * in the signature — everything after it is keyword-only. def f(a, *, b) accepts f(1, b=2) but rejects f(1, 2) with a TypeError. Minimal working example: python keyword-only arguments with bare * def create_user(name, *, role="user", active=True): return {"name": name, "role": role, "active": active} print(create_user("ada", role="admin")) # {'name': 'ada', 'role': 'admin', 'active': True} print(create_user("ada", active=False, role="mod")) # {'name': 'ada', 'role': 'mod', 'active': False} — order doesn't matter create_user("ada", "admin") # TypeError: create_user() takes 1 positional argument but 2 were given The * is a separator, not a parameter. Everything to its left ( name ) can be passed positionally or by keyword; everything to its right ( role , active ) *must* be passed by keyword. That's the whole mechanism — one character that turns ambiguous positional calls into self-documenting ones. Why this matters in practice: positional flags are the number-one source of misread call sites. process(data, True, False) tells the reader nothing; process(data, normalize=True, cache=False) explains itself, and keyword-only enforcement means nobody on your team can accidentally write the unreadable version. Variations 1. Keyword-only with defaults — the common real-world shape. Flags and options that callers should always name: def connect(host, *, port=5432, ssl=True, timeout=30): return f"{host}:{port} ssl={ssl} timeout={timeout}" print(connect("db.internal", ssl=False)) # db.internal:5432 ssl=False timeout=30 print(connect("db.internal", 5433, True)) #…