Since Python 3.8, you can use a slash / in the argument list when defining a function. This syntax is used to define “Positional-Only Arguments.” By using this, you can prohibit specific arguments from being called as keyword arguments and force them to be passed only as positional arguments (by value order).
This is useful when defining functions where the “order” of arguments is more important than their names, such as built-in functions like len(obj) or pow(x, y). This article explains how to write positional-only arguments and their benefits.
How to Write Positional-Only Arguments
In the function definition’s argument list, if you place a / (slash), all arguments to its left become “positional-only.”
Syntax:
def function_name(pos_only1, pos_only2, /, normal_args):
# Process
Specific Example
As an example, let’s create a function that takes a year, month, and day and returns a formatted date string. For data like dates, it is often more natural to write 2025, 11, 20 in order rather than year=2025.
def format_date(year, month, day, /, separator="-"):
"""
Receives year, month, and day as positional arguments
and joins them with the specified separator.
"""
return f"{year}{separator}{month:02}{separator}{day:02}"
# --- Correct Usage ---
# year, month, day must be passed as positional arguments (left of /)
date_str = format_date(2025, 11, 20)
print(f"Date: {date_str}")
# 'separator' is a normal argument, so keyword specification is possible
date_slash = format_date(2025, 11, 20, separator="/")
print(f"Slash Separated: {date_slash}")
Output:
Date: 2025-11-20
Slash Separated: 2025/11/20
Invalid Usage (Error)
If you try to specify arguments to the left of / as keyword arguments, a TypeError will occur.
# Error Example: Specifying positional-only arguments as keywords
# format_date(year=2025, month=11, day=20)
# TypeError: format_date() got some positional-only arguments passed as keyword arguments: 'year', 'month', 'day'
This allows you to enforce the constraint on the caller: “These arguments must be passed in order.”
Why Use Positional-Only Arguments? (Benefits)
While it might seem like an inconvenient restriction at first glance, it offers several benefits for library development and API design:
- Freedom to Change Argument Names: Since the caller does not rely on argument names (like
year), you can refactor the internal argument names without breaking the user’s code (e.g.,format_date(2025, ...)). - Avoid Conflicts with Keyword Arguments: When using
**kwargs(variable-length keyword arguments), this prevents the positional argument names from colliding with keys inkwargs. - Improved Readability: When the meaning of an argument is self-evident (e.g.,
objinlen(obj)), not forcing the user to write the name makes the code cleaner.
Combining All Argument Types
In Python, you can mix three types: “Positional-Only,” “Normal (Positional or Keyword),” and “Keyword-Only.” The order is as follows: def f(pos_only, /, normal, *, kw_only):
def complex_function(a, b, /, c, *, d):
print(a, b, c, d)
# a, b : Positional only
# c : Positional or Keyword OK
# d : Keyword only
complex_function(1, 2, 3, d=4) # OK
complex_function(1, 2, c=3, d=4) # OK
# complex_function(a=1, 2, 3, d=4) # NG (a is positional-only)
# complex_function(1, 2, 3, 4) # NG (d is keyword-only)
Summary
- The
/in the function definition argument list makes arguments to its left “Positional-Only.” - Positional-only arguments cannot use the
arg=valueformat when called; they must be passed by order. - This is effective when you want to avoid the impact of changing argument names or when the meaning of arguments is obvious.
