Positional and Keyword Arguments in Python

Master the two ways to pass arguments to Python functions: by position and by keyword. Learn the rules for mixing them and when to choose each style.

7 min read

The article on Python function parameters and arguments introduced the core concepts: parameters are placeholders in the definition, arguments are the values passed at the call site, and Python supports both positional and keyword argument styles. Now it is time to go deeper into the rules that govern how these two styles interact, when you should choose one over the other, and how modern Python lets you enforce specific calling conventions through syntax in the function signature itself.

Positional arguments have been the default since Python's earliest versions, and they remain the most common argument style for simple functions. Keyword arguments were added to give callers more control and readability, and Python 3.8 introduced the slash syntax for positional-only parameters, completing the set of tools that let function authors specify exactly how each parameter must be passed. Understanding all three mechanisms, positional, keyword, and the enforcement syntax, is what lets you design function interfaces that are both easy to call correctly and hard to call incorrectly.

How positional arguments work under the hood

When Python executes a function call, it processes positional arguments first. Each positional argument is assigned to the corresponding parameter by its index: the first argument goes to the first parameter without a default value that has not already received a keyword argument, the second goes to the next available parameter, and so on. This matching is purely positional and does not consider parameter names at all.

The practical implication is that changing the order of parameters in a function definition silently changes the meaning of positional arguments at every call site. If a function originally took parameters in the order def process(source, target) and you later change it to def process(target, source), every call that uses positional arguments will now pass the values to the wrong parameters, and Python will not warn you because both parameters are likely strings and the types are compatible. This fragility is the primary motivation for using keyword arguments at call sites where parameter order is not obvious.

Positional arguments also interact with default parameter values in a specific way. Python fills required parameters first, from left to right, using the positional arguments. Optional parameters with defaults are only filled if positional arguments remain after all required parameters have been assigned. This is why parameters with defaults must appear after required parameters in the definition: if a required parameter appeared after an optional one, the caller could not skip the optional parameter without also skipping the required one, which would defeat the purpose of having a default.

How keyword arguments work under the hood

Keyword arguments are processed after all positional arguments have been assigned. Python matches each keyword argument to its parameter by name, ignoring position entirely. If a keyword argument names a parameter that has already received a value from a positional argument, Python raises a TypeError with the message "got multiple values for argument." This error is a safety feature that prevents a single parameter from receiving conflicting values through two different argument-passing mechanisms.

Keyword arguments are especially valuable when a function has many parameters with default values and the caller only needs to override a few of them. A function that formats a date might accept parameters for the format string, the locale, the timezone, and the output encoding, all with sensible defaults. A caller who only needs a different timezone can pass timezone="UTC" as a keyword argument and let all the other parameters keep their defaults. Without keyword arguments, the caller would need to specify every parameter up to the timezone in positional order, even though most of them would just repeat the defaults.

The names you choose for parameters become part of the function's public interface when callers use keyword arguments, because those names appear in every call site. Renaming a parameter means updating every call site that uses it as a keyword argument. This is a good thing, it forces you to think about parameter names as part of the API design rather than as internal implementation details, but it also means you should choose parameter names carefully and avoid changing them without good reason.

The ordering rules for mixed argument styles

Python enforces strict ordering when a call mixes positional and keyword arguments. All positional arguments must appear first, followed by all keyword arguments. This rule exists to prevent ambiguity: if keyword arguments could appear before positional arguments, it would be unclear which parameter an unlabeled value was meant to fill. The parser rejects mixed-order calls with a syntax error before the code even runs.

Once a keyword argument appears in a call, every argument after it must also be a keyword argument. You cannot follow a keyword argument with a positional argument, even if the positional argument targets a different parameter. This rule also prevents ambiguity and is enforced by the parser. The result is that function calls with mixed argument styles have a clear visual structure: unlabeled values first, labeled values after.

A common pattern in real Python code is to pass the most important or most obvious arguments positionally and the less common or less obvious arguments by keyword. A function that reads a file might take the file path as the first positional argument and optional parameters for encoding, buffering, and error handling as keyword arguments. The call open("data.txt", encoding="utf-8") reads naturally: the file name is obvious by position, and the encoding specification benefits from the explicit label.

Enforcing positional-only parameters with the slash

Python 3.8 introduced the slash (/) as syntax for marking parameters as positional-only. Any parameter that appears before the slash in the function definition cannot be passed as a keyword argument. Attempting to do so raises a TypeError:

pythonpython
def process(data, /, verbose=False):
    print(f"Processing {data}")
    if verbose:
        print("Verbose output enabled")

The data parameter is positional-only because it appears before the slash. Callers must pass it by position. The verbose parameter appears after the slash and can be passed by position or by keyword. Positional-only parameters are useful when the parameter name is an implementation detail that should not become part of the public API, or when the name would be meaningless or confusing to callers. Many built-in Python functions use positional-only parameters for exactly this reason.

Enforcing keyword-only parameters with the asterisk

Placing a bare asterisk (*) in the parameter list makes all subsequent parameters keyword-only. They must be passed by name, and attempting to pass them positionally raises a TypeError:

pythonpython
def configure(*, host, port, debug=False):
    print(f"Server at {host}:{port}, debug={debug}")
 
configure(host="localhost", port=8080)

The asterisk in the parameter list consumes no arguments itself; it simply acts as a marker that everything after it is keyword-only. Keyword-only parameters are useful for values whose meaning would not be clear from position alone. A boolean flag passed as True or False in the middle of a call is ambiguous, but debug=True tells the reader exactly which behavior is being enabled. The article on default parameter values in Python functions explores this pattern further, especially how keyword-only parameters combine with defaults to create clear, safe function interfaces.

Choosing between positional and keyword at the call site

As the caller of a function, you decide whether to pass each argument positionally or by keyword, within the constraints set by the function's signature. For functions with one or two obvious parameters, positional calls are concise and natural. For functions with many parameters, especially when most have defaults, keyword arguments make the call readable without forcing the reader to look up the function definition.

A useful guideline: if you are calling a function and a reader would need to check the definition to understand what an argument means, pass it as a keyword argument. The label serves as inline documentation. If the meaning is obvious from the value alone, a positional argument is fine. This guideline keeps short calls concise while ensuring that complex calls remain understandable. The Python standard library itself follows this pattern, with functions like sorted accepting the iterable as a positional argument and optional parameters like key and reverse as keyword arguments.

Rune AI

Rune AI

Key Insights

  • Positional arguments are matched to parameters by their order in the function call; keyword arguments are matched by name.
  • Positional arguments must come before keyword arguments in any function call; this rule is enforced by the parser.
  • Use the / symbol to mark parameters as positional-only and the * symbol to mark parameters as keyword-only.
  • Keyword arguments make function calls self-documenting and free callers from remembering parameter order.
  • A parameter cannot receive both a positional and a keyword argument in the same call; Python raises a TypeError.
RunePowered by Rune AI

Frequently Asked Questions

When should I use keyword arguments instead of positional arguments?

Use keyword arguments when a function has many parameters and callers might not remember the order, when only a few of the parameters need non-default values, or when you want the function call to be self-documenting. Keyword arguments make calls more readable at the cost of being slightly more verbose. Use positional arguments for short functions with one or two obvious parameters.

What does the slash (/) in a Python function signature mean?

The slash indicates that all parameters before it are positional-only. They cannot be passed as keyword arguments. This is used for parameters whose names are implementation details that should not become part of the function's public API, or when the parameter name would not be meaningful to callers.

Can I force callers to use keyword arguments for certain parameters?

Yes. Place an asterisk (*) in the parameter list. All parameters after the asterisk are keyword-only and must be passed by name. This is useful for parameters where the meaning would be unclear from position alone, or for boolean flags whose purpose is not obvious from a True or False value.

Conclusion

Positional and keyword arguments are not competing styles; they are complementary tools that serve different purposes. Positional arguments are concise and natural for short function calls with obvious parameter order. Keyword arguments add clarity and flexibility when functions grow in complexity. Understanding the rules for mixing them and knowing when to enforce one style over the other gives you precise control over how callers interact with your functions.