Python Positional-Only Parameters Explained
Positional-only parameters, introduced in Python 3.8 via PEP 570,
allow developers to specify function arguments that must be supplied by
position rather than as keyword arguments. In a function signature, the
forward slash (/) acts as a delimiter indicating that all
parameters to its left cannot be passed using name=value
syntax. This article explores why the slash syntax exists, its primary
design advantages, and how it improves API design and code
stability.
The Syntax of the Slash
(/)
In Python, the forward slash divides parameters into positional-only and standard parameters. When defining a function:
def example(a, b, /, c, d, *, e, f):
passaandbare positional-only (must be passed as values only).canddcan be passed by position or keyword.eandfare keyword-only (marked by*, must be passed asname=value).
Calling example(a=1, b=2, c=3, d=4, e=5, f=6) will raise
a TypeError because a and b
cannot be supplied as keyword arguments.
1. API Stability and Name Decoupling
The primary significance of positional-only parameters is decoupling an API's implementation from its public contract. When arguments can be passed by keyword, parameter names become part of the public interface. If an author renames a parameter in a later release, any caller relying on the old keyword name will experience broken code.
By marking parameters with /, authors reserve the right
to rename parameters in future refactors without breaking backwards
compatibility:
# The parameter name 'x' can be renamed to 'value' later without breaking callers
def square(x, /):
return x ** 2
# Valid call
square(5)
# Raises TypeError: square() got some positional-only arguments passed as keyword arguments: 'x'
square(x=5)2. Preventing Collisions
with **kwargs
When a function accepts arbitrary keyword arguments via
**kwargs, named parameters can create ambiguous namespace
conflicts. Positional-only parameters eliminate this problem.
Consider a function that formats data using arbitrary keyword pairs:
def format_entry(template, /, **kwargs):
return template.format(**kwargs)Because template is positional-only, a caller can safely
pass a keyword argument named template inside
kwargs without causing a collision:
# This works seamlessly
format_entry("Template name: {template}", template="BaseTheme")Without the /, Python would raise a
TypeError: format_entry() got multiple values for keyword argument 'template'.
3. Emulating Built-In C Functions
Historically, many built-in functions implemented in C (such as
len(), abs(), and min()) only
accepted positional arguments. Before Python 3.8, pure Python functions
could not replicate this behavior natively, leading to inconsistencies
between built-in APIs and user-defined functions. The /
syntax standardizes function signature capabilities across both pure
Python and C-extension modules.
4. Enforcing Natural and Readable Call Semantics
Some arguments have obvious positional meaning, and forcing or allowing them to be passed as keywords adds noise or confusion rather than clarity. For example, mathematical coordinates or transformations:
def calculate_distance(x1, y1, x2, y2, /):
...Calling calculate_distance(0, 0, 10, 10) is idiomatic
and clean, whereas allowing calls like
calculate_distance(x2=10, y1=0, x1=0, y2=10) degrades
readability without providing any practical benefit.