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:
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:
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
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.
Frequently Asked Questions
When should I use keyword arguments instead of positional arguments?
What does the slash (/) in a Python function signature mean?
Can I force callers to use keyword arguments for certain parameters?
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.
More in this topic
Define and Call Python Functions
Learn the exact syntax for defining and calling Python functions with the def keyword, including naming rules, the function body, and how the call stack works.
Python Function Parameters and Arguments
Learn the difference between parameters and arguments, how to pass values by position and by keyword, and the rules for default parameter values.
Python Functions Explained
Learn what Python functions are, why they matter for organizing code, and how they form the foundation of non-trivial programs.