Python Positional Arguments: Order and Binding Rules
python positional arguments: Learn how Python positional arguments bind by order, mix with keyword arguments, and use *args or positional-only syntax for cleaner APIs.
What Positional Arguments Are
Python positional arguments are values passed to a function call that are matched to parameters by their position in the call. The first value binds to the first parameter, the second value to the second parameter, and so on. This is the default way arguments are passed in Python, and it is the simplest form of function invocation.
def connect(host, port, timeout): return f"{host}:{port} (timeout={timeout})" result = connect("api.example.com", 443, 30)
In this call, "api.example.com" binds to host, 443 binds to port, and 30 binds to timeout. The parameter names play no role in the binding; only the order of the values matters.
How Order Determines Binding
Because binding is purely positional, the order of values in the call directly determines which parameter receives which value. Swapping two arguments changes the behavior of the call, often in ways that are hard to spot during review.
def resize(width, height, quality): return f"{width}x{height}, quality={quality}" # Correct resize(1920, 1080, 85) # Both values are swapped; the image dimensions are wrong resize(1080, 1920, 85)
The second call does not raise an error. It silently produces a result with the width and height exchanged. This is the main risk of relying on positional arguments: the interpreter cannot detect that the values are in the wrong order when the types are the same.
Mixing Positional and Keyword Arguments
Python allows a call to mix positional and keyword arguments, but the syntax rules are strict. Every positional argument must appear before the first keyword argument. Once a keyword argument is used, all remaining arguments must also be keyword arguments.
connect("api.example.com", port=443, timeout=30) # valid connect(host="api.example.com", 443, 30) # SyntaxError
A second constraint is that a parameter cannot receive a value twice. Passing the same parameter both positionally and by keyword raises a TypeError at call time.
connect("api.example.com", 443, port=443) # TypeError: connect() got multiple values for argument 'port'
These rules exist so the binding is always unambiguous. The interpreter can always determine which parameter each argument targets.
Variable Positional Arguments with *args
When a function must accept an arbitrary number of positional arguments, the *args parameter collects them into a tuple. The name args is a convention, not a requirement; any name after the * works, but args is the widely understood default.
def log(level, *messages): for message in messages: print(f"[{level}] {message}") log("INFO", "started", "connecting", "done")
Here level receives "INFO", and the remaining three strings are collected into the tuple messages. The *args parameter must appear after the regular parameters. Any parameter declared after *args can only be passed as a keyword argument, because *args consumes all remaining positional values.
def configure(host, *ports, retries=3): ... configure("api.example.com", 80, 443, retries=5) # retries=5 configure("api.example.com", 80, 443, 5) # 5 goes into ports; retries stays 3
Positional-Only Parameters with /
Python 3.8 added positional-only parameters, marked by a / in the parameter list. Every parameter before the / can only be passed positionally; attempting to pass them by keyword raises a TypeError.
def divide(numerator, denominator, /): return numerator / denominator divide(10, 2) # valid divide(numerator=10, denominator=2) # TypeError
Positional-only parameters are useful when the parameter names are not part of the public contract. This gives the implementation freedom to rename parameters later without breaking callers who use keyword arguments. Standard library functions such as len and range use this style for the same reason.
Choosing Positional or Keyword Arguments in API Design
The decision between positional and keyword arguments changes how callers read and maintain the code. Positional arguments keep calls short and are appropriate when the order is obvious, the function has few parameters, and every parameter is required. Keyword arguments make calls longer but self-documenting, which matters when a function has many parameters or several optional ones with defaults.
A practical rule is to use positional arguments for the first one or two required parameters whose meaning is obvious from context, and keyword arguments for everything else. Functions with more than three or four parameters become hard to call positionally because the reader must remember the order.
Positional-only parameters are a stronger constraint: they prevent callers from using keywords entirely. Use them when the parameter name is an implementation detail and you want to reserve the right to change it. Keyword-only parameters, declared after a bare *, are the opposite: they force callers to use keywords, which is useful for boolean flags and other values whose meaning is not clear from position alone.
Common Errors and Their Causes
Three errors dominate real-world usage of positional arguments.
A TypeError: missing required positional argument appears when a call provides fewer values than the function has required parameters. The interpreter reports the missing parameter by name, which makes the fix straightforward: supply the value or give the parameter a default.
A TypeError: takes X positional arguments but Y were given appears when a call provides more values than the function accepts. This happens when a function signature was changed and callers were not updated, or when a value that should be part of a collection is passed as a separate argument.
A SyntaxError: positional argument follows keyword argument is a parser error, not a runtime error. It occurs when a call places a positional value after a keyword argument, which the language forbids. Reordering the call so all positional arguments come first resolves it.
These errors are all detected either at parse time or call time, so they do not cause silent data corruption. The silent failure mode is the swapped-argument bug described earlier, which is why functions with several same-typed parameters are better designed with keyword arguments or keyword-only parameters.