Python Keyword-Only Parameters: Syntax and Use Cases
python keyword only parameters: Learn how to define Python keyword-only parameters with the * separator, and when they improve API clarity and prevent argument order m...
Python keyword only parameters let you force callers to pass certain arguments by name, which is useful when the meaning of an argument is not obvious from its position. This feature is part of the function signature syntax and has been available since Python 3.0, though it is often overlooked in favor of more common parameter patterns.
What Keyword-Only Parameters Are
A keyword-only parameter is one that must be supplied as a keyword argument in a function call. You mark parameters as keyword-only by placing a bare * in the parameter list. Everything after that * is keyword-only. The * itself is not a parameter; it is a separator that tells the parser to treat the following parameters as keyword-only.
For example:
def configure_server(host, port, *, timeout=30, retries=3): ...
Here host and port are positional parameters, while timeout and retries are keyword-only. A call like configure_server("localhost", 8080, 30) raises a TypeError because 30 is interpreted as a positional argument for timeout, which is not allowed. The correct call is configure_server("localhost", 8080, timeout=30, retries=3).
Declaring Keyword-Only Parameters
The syntax is straightforward: place a * in the parameter list before the parameters you want to make keyword-only. You can have positional parameters before the *, and you can also have *args to capture extra positional arguments. When *args is present, the parameters after it are automatically keyword-only. For instance:
def log_message(level, message, *args, timestamp=None): ...
In this signature, level and message are positional, args collects any additional positional arguments, and timestamp is keyword-only. You can call it as log_message("ERROR", "Disk full", timestamp=1234567890). If you try to pass timestamp positionally, Python raises an error.
Why Enforce Keyword Arguments
The primary motivation is readability. When a function has many parameters, especially ones with default values, it is easy to misplace arguments. Requiring keyword arguments for optional settings makes the call site self-documenting. Compare:
configure_server("localhost", 8080, 30, 3)
with:
configure_server("localhost", 8080, timeout=30, retries=3)
The second version is clearer because it names the values. This becomes even more important when parameters have subtle meanings, such as use_ssl or max_connections. Keyword-only parameters also protect against accidental positional misordering when the function signature changes over time.
Combining with Default and Positional Parameters
You can mix positional, keyword-only, and *args in the same signature. The * can be used alone to mark the boundary, or you can use *args to capture extra positional arguments. If you use *args, the parameters after it are keyword-only by definition. For example:
def send_request(url, method='GET', *, headers=None, timeout=10): ...
Here url is positional, method is positional with a default, and headers and timeout are keyword-only. A call like send_request("https://api.example.com", "POST", headers={"Content-Type": "application/json"}) is valid. You cannot pass headers positionally.
Common Mistakes and Pitfalls
A frequent mistake is forgetting the * and assuming that parameters after a default value are automatically keyword-only. They are not; they can still be passed positionally unless you explicitly add the *. Another pitfall is placing * after **kwargs, which is invalid because **kwargs must be the last parameter. Also, using a bare * without any following parameters is allowed but has no effect; it simply prevents any positional arguments after that point, which is rarely useful.
A more subtle issue is that keyword-only parameters cannot be passed positionally even if they have default values. This is a deliberate design choice to enforce clarity, but it can break existing code if you add a * to a function that previously allowed positional arguments for those parameters.
Performance and Maintainability
Keyword-only parameters have no runtime performance cost. The enforcement is a simple check during function call resolution, and the overhead is negligible. The real benefit is maintainability. Because keyword-only parameters are passed by name, changing their order does not break callers. You can also add new keyword-only parameters without affecting existing calls, as long as they have default values. This is especially valuable in public APIs and frameworks where backward compatibility matters.
For example, if you have a function:
def connect(host, port, *, timeout=30): ...
You can later add retries=3 without breaking existing calls. Existing callers that use connect("localhost", 8080, timeout=5) continue to work. If timeout were positional, adding a new parameter before it would break every call.
Using Keyword-Only in Class Constructors
The same syntax applies to __init__ and other methods. This is common in configuration classes or dataclasses where you want to prevent accidental positional misordering. For example:
class ConnectionConfig: def __init__(self, host, port, *, timeout=30, use_ssl=True): self.host = host self.port = port self.timeout = timeout self.use_ssl = use_ssl
Instantiating ConnectionConfig("localhost", 8080, timeout=10, use_ssl=False) is explicit and safe. If you later add another optional parameter, existing constructor calls remain valid as long as they use keyword arguments for the optional ones.
When Not to Use Keyword-Only
Keyword-only parameters are not always the right choice. If a function has only a few parameters and their order is obvious, forcing keyword arguments can add noise. For example, a simple function like def add(a, b): does not benefit from keyword-only parameters. Also, if you need to maintain compatibility with existing positional calls, adding a * is a breaking change. Use keyword-only parameters when the function signature is likely to grow, when parameters have subtle meanings, or when you are designing a public API that should be self-documenting.
In practice, the decision comes down to balancing clarity against flexibility. If the function is internal and used in a few places, positional arguments may be fine. For public APIs, keyword-only parameters are often a good investment because they make the interface more robust to change and easier to read.