AlgoMaster Logo

Keyword Arguments

Medium Priority21 min readUpdated June 6, 2026
Listen to this chapter
Unlock Audio

Every Python function call passes arguments either by position (the order they appear) or by name (parameter=value). Named calls survive refactors, document the call site, and let you skip parameters that have defaults. Python also provides a way to require named calls (keyword-only parameters) and a way to forbid them (positional-only parameters), so function signatures can be shaped around how they should be used. This lesson covers the call-site choice, the rules for mixing positional and keyword arguments, and the two markers (* and /) that pin down which kind a parameter accepts.

Two Ways to Pass an Argument

A function defined with regular parameters accepts both positional and keyword calls. Take this small order-pricing function:

All three calls produce the same value. The first call relies on the reader to know that the first argument is the quantity, the second is the price, and the third is the discount. The second call says so explicitly. The third call mixes the two: positional for the first two, keyword for the last.

The positional version is shorter, and for a function with two or three obvious parameters that's often fine. The keyword version is longer but reads on its own. price_order(3, 29.99, 0.10) requires knowing the signature to understand it. price_order(quantity=3, unit_price=29.99, discount=0.10) explains itself at the call site.

A keyword call also lets you pass arguments in any order, because Python matches by name instead of position:

The values land in the right slots regardless of the order at the call site. That flexibility matters less than it sounds (a consistent order still aids readability), but it's the foundation for the rules that follow.

Mixing Positional and Keyword Arguments

The two styles can mix in one call, with one rule: positional arguments come first, keyword arguments come last. Once a name=value appears, every argument after it has to be a keyword too.

The order between positional arguments still matches the parameter order. "alice" lands in customer because it's first; "Wireless Mouse" lands in product because it's second. The keyword arguments fill in by name, so quantity=2 and gift_wrap=True can appear in either order without changing the result.

Putting a positional after a keyword is a SyntaxError:

The parser flags it before the program runs. The fix is to either move the positional before the keyword (add_to_cart("alice", "Wireless Mouse", 2, True)) or convert it to a keyword (add_to_cart("alice", product="Wireless Mouse", quantity=2, gift_wrap=True)).

A subtler error happens when the same parameter is passed twice, once positionally and once by name:

"alice" already filled customer positionally, and then customer="bob" tried to fill it again. Python raises an error rather than picking one. The fix is straightforward: don't bind the same parameter twice.

Why Use Keyword Arguments

Three things make keyword arguments more than a stylistic choice.

The first is readability at the call site. A function with two or three parameters that all mean obvious things can stand a positional call. A function with five booleans cannot. Compare these:

The positional version is shorter by a wide margin, but it can't be read without the signature in front of you. Booleans, in particular, are a magnet for keyword-argument style: gift_wrap=True says what's on; a bare True doesn't.

The second is refactoring safety. If a function reorders its parameters in a new version, every positional call has to change with it. Keyword calls keep working as long as the names stay stable.

The positional call still runs but produces a nonsense number because the second argument is now a discount, not a price. The keyword call doesn't depend on order, so it survives the change.

The third is skipping parameters with defaults. When some parameters have defaults, keyword calls let the caller set only the ones that matter and leave the rest alone.

Without keyword arguments, every default to keep would need an explicit placeholder, as in older languages. With keywords, set what's meant and leave the rest.

Keyword argument dispatch is slightly slower per call than positional dispatch (Python has to match names against the signature), but the difference is well under a microsecond and rarely matters. Pick the style that reads, not the one that's measurably faster.

Keyword-Only Parameters

Some functions have parameters that shouldn't be passed by position. Boolean flags, configuration knobs, and rarely-set options usually fall in this group. Python lets such parameters be marked as keyword-only: parameters the caller is required to pass by name, even when they have defaults.

The marker is a single * in the parameter list. Every parameter to the right of the * is keyword-only.

The * doesn't bind to a parameter itself; it's a marker that says "no more positional arguments past here". customer and items are still ordinary parameters and can be passed positionally or by name. delivery and gift_wrap can only be passed by name.

Passing a keyword-only parameter positionally is an error:

The function accepts exactly two positional arguments (customer and items). The other two arguments have to come in by name. The error message points at "2 positional arguments", which is exactly what the * enforces.

Any parameter that sits between *args and **kwargs is also keyword-only, because all the positional slots are already absorbed by *args. The bare * is the same idea without collecting anything; it's a fence.

*items collects extra positionals, and level and target sit after it, so they're keyword-only. The call site reads cleanly: the items come first, the named options come after.

Keyword-only parameters have one other property: they don't need defaults. A keyword-only parameter without a default is a required keyword argument, meaning the caller has to pass it by name and can't omit it.

Required keyword arguments are a useful pattern when omitting a value would be dangerous (transferring zero by accident) or when the argument's meaning is ambiguous without its name (amount=100 versus 100). The function refuses to run unless the caller is explicit.

The orange parameters accept either style. The red * is the fence (not a real parameter). The green parameters can only come in by name.

Positional-Only Parameters

The opposite marker is /, which makes the parameters to its left positional-only. The caller cannot pass them by name. This was added in Python 3.8 by PEP 570.

The / is a marker, not a parameter. Everything to its left is positional-only. The first call works because it passes the list positionally. The second call uses the name prices, which Python rejects because that name isn't part of the public interface.

There are three reasons to use this.

The first is mirroring built-ins. Built-in functions like len, abs, pow, and divmod accept positional arguments only, and they always have. len(obj=mylist) isn't valid because the obj name isn't part of the contract. PEP 570 gave pure-Python functions the same ability, so a library can write a function that behaves like a built-in.

The second is allowing parameter renames. If a parameter is positional-only, the function can rename it in a new version without breaking any caller, since the old name was never visible at call sites. This matters for library maintainers cleaning up parameter names without forcing a breaking change.

The third is freeing the name for `kwargs`. If a function takes `kwargs` and one of its real parameters has a common name like name or id, callers might want to pass name="alice" as part of the kwargs. Marking the real parameter positional-only lets the same call work for both purposes.

Without /, the second call would bind name="primary" to the parameter and crash because "Wireless Mouse" already filled it. With /, the parameter name is positional-only and the keyword name in the call ends up inside **attributes cleanly.

Positional-only is a library-design tool, not something for everyday application code. For a function called from one or two places in the same codebase, regular parameters are fine. For a published API with external callers, / provides the freedom to refactor parameter names later.

The / has no runtime cost. It's a compile-time marker. The interpreter uses it to decide which call shapes are legal, but once the function runs, positional-only parameters are regular local names.

The Full Parameter Signature

Combining the two markers gives the most general shape of a Python function signature. From left to right:

  1. Positional-only parameters (before /).
  2. The / marker.
  3. Parameters that accept either style (after / and before *).
  4. *args (or a bare * to mark the rest as keyword-only).
  5. Keyword-only parameters (after * or *args).
  6. **kwargs.

Not every signature uses all the slots, and most don't. A typical function might use slots 3 and 5; a library API might use 1, 3, 5, and 6. The order is fixed; slots can be omitted but not reordered.

A contrived but legal signature that uses every slot:

Reading this signature: customer is positional-only (before /), items can be passed either way (between / and *), delivery is keyword-only with a default (after *), and **options collects any other keyword arguments. The two calls show the shape: customer always comes in positionally, items can be either, delivery is always named, and extra named arguments fall through to options.

Most signatures don't need this much machinery. Use the markers when:

  • A parameter should require a name at the call site (use * and put it after).
  • A parameter should forbid a name at the call site (use / and put it before).
  • The code is a library API where parameter renames or **kwargs collisions are a real concern.

For everyday application code, regular parameters with sensible defaults cover the vast majority of cases.

The diagram shows the order Python expects. Any of the boxes can be omitted, but the ones kept must appear in this sequence.

Defaults Interact with Keyword Calls

A default doesn't change whether a parameter is positional, keyword, or both. The position in the signature decides that. But defaults make keyword calls more powerful, because the caller can set only the ones that matter and leave the rest at their defaults.

The first two calls produce identical output. Both set delivery to "express", but the keyword version reads better and would survive a parameter reorder. The third call sets only gift_wrap, which is the third default; without keywords, "standard" would need to be passed explicitly for delivery first.

For a function with many defaults, keyword calls keep most calls short. Few callers pass all six parameters; most pass two or three with the ones that matter, and the defaults fill the rest.

Defaults and keyword calls work together: defaults make parameters optional, and keyword calls skip the optional ones cleanly.

Forwarding via **kwargs

**kwargs collects arbitrary keyword arguments. It's also the standard way to forward keyword arguments to another function without listing them out. This pattern shows up in wrapper functions, decorators, and any code that passes options through to a delegate.

place_order_logged doesn't need to know which options place_order supports. It collects them all into options, then unpacks them with **options when calling the real function. If place_order adds a new option (signature_required, say), the wrapper keeps working without any code change.

The forwarding pattern works because keyword arguments match by name. A positional-only forwarder would have to know the exact parameter order, and any change to place_order would break it. Keyword forwarding survives signature changes as long as the names stay stable.

Forwarding with **kwargs builds a dict per call. For most code this is invisible. For a function called in a tight inner loop, the wrapper adds a small constant overhead per call; profile before assuming it matters.

One catch with forwarding: if the wrapper and the delegate share a parameter name, it can't be passed twice. This produces a TypeError: got multiple values for keyword argument. The fix: ensure each keyword binds to exactly one parameter, either by filtering the dict or by changing one of the function signatures.

API Design Considerations

Choosing positional, keyword, or required-keyword shapes is part of designing a function's public face. A few patterns hold up well.

Booleans should be keyword-only. A bare True or False at a call site is almost always opaque. place_order(items, customer, True, False, True) could mean anything. place_order(items, customer, gift_wrap=True, express=False, signature_required=True) reads like prose. For a function with two or more booleans, mark them keyword-only with *.

Required parameters with no obvious order should be keyword-only. If a function has three parameters of the same type (three floats, three strings), the call site doesn't show what each one means. Forcing keywords makes the meaning explicit.

The first one or two parameters can be positional. When a function operates on a primary value (a list, a customer, a request), letting that primary value be positional is fine. cart_total(cart) and cart_total(items=cart) are equally readable; the positional version is shorter.

Optional configuration belongs in keyword-only territory. Anything that adjusts behavior rather than describing the main input is usually clearer as a keyword argument. Sort comparators, timeouts, retry counts, feature flags: pass them by name.

Use `/` only when there's a reason. Most application code doesn't need positional-only parameters. Use / when publishing a library API that needs the freedom to rename parameters later, or when a parameter name collides with something that belongs in **kwargs.

These are guidelines, not laws. The standard library and most major Python libraries follow them loosely, with exceptions where the convention would be silly. The underlying principle is the same: shape the signature so that call sites read clearly without the signature in front of them.

Quiz

Keyword Arguments Quiz

10 quizzes