What is the difference between * and / in a function signature (keyword-only and positional-only)?
In modern Python development, controlling how functions are called is a critical tool for designing a reliable interface. To achieve this, function signatures use special slash and asterisk symbols, which divide parameters into positional, keyword, and universal ones. Understanding this mechanics allows developers to write flexible code and safely evolve public APIs without the risk of breaking end-user logic.
The slash symbol in a function signature indicates that all arguments located to its left are exclusively positional. This means that when calling the function, the user must pass them in order without using parameter names. For example, if you declare a function f(a, /, b), the first argument can only be passed as a value, while the second argument can be specified either by position or by name. This approach is useful when internal parameter names carry no semantic meaning for the calling code or when you plan to change the variable name inside the function in the future without breaking compatibility.
The asterisk symbol performs the opposite task, requiring all arguments located to its right to be passed exclusively as keyword arguments. For example, in the signature f(*, x, y), the parameters x and y cannot be passed simply by order; their names must be explicitly specified when calling the function. This protects the code from confusion in cases where a function accepts many similar arguments or configuration flags whose meanings are not obvious without explicitly stating their names.
Combining these symbols in a single signature allows you to fully control the interaction interface with the function. For example, writing f(pos_only, /, standard, *, kw_only) creates three distinct zones for arguments: positional-only, universal, and keyword-only. In practice, this significantly reduces the number of accidental errors when calling functions, helps maintain API backward compatibility during library updates, and is frequently used in the Python standard library and professional framework code to ensure maximum software stability.