dataclasses.KW_ONLY: Require Keyword-Only Arguments

Published on: September 8, 2026
Reading time: 5 minutes
Software developer building models with Python dataclasses.KW_ONLY

dataclasses.KW_ONLY lets a dataclass define a boundary after which fields must be supplied by name. This makes constructors easier to read, prevents ambiguous calls, and gives public APIs more room to evolve without breaking existing code. Instead of relying on a long positional sequence, you can require callers to spell out sensitive or optional parameters.

This guide explains how KW_ONLY works, how it differs from kw_only=True, and how it interacts with inheritance, defaults, __match_args__, structural pattern matching, and dataclasses.replace. It also covers practical design rules and common mistakes.

The positional argument problem

Imagine a configuration class with several booleans and integers. A call such as Config('prod', True, False, 30) is difficult to understand without opening the class definition. Swapping two values of the same type may not raise an exception, yet it can silently change behavior.

A keyword-oriented call is clearer: Config('prod', debug=True, cache=False, timeout=30). The code documents its own intent, and future field reordering is less likely to introduce subtle regressions.

How to use dataclasses.KW_ONLY

KW_ONLY is a type marker. Add a pseudo-field, conventionally named _, and every field declared after it becomes keyword-only.

from dataclasses import dataclass, KW_ONLY

@dataclass
class Service:
    name: str
    _: KW_ONLY
    timeout: int = 30
    retries: int = 3
    debug: bool = False

api = Service('payments', timeout=10, retries=5)

The marker is not stored on instances, does not appear in the representation, and never receives a value. Its only job is to divide positional fields from named fields.

Calling Service('payments', 10, 5) raises TypeError because timeout and retries must be passed by name.

KW_ONLY versus kw_only=True

The decorator option @dataclass(kw_only=True) makes every field keyword-only. It is a good choice when positional construction does not improve the API. KW_ONLY is more selective: it preserves a few essential positional fields while requiring names for the remaining options.

A useful rule is to keep positional only the fields that clearly identify the object and are unlikely to move. Flags, limits, policies, credentials, and future extension points are usually safer as keyword-only fields.

Required keyword-only fields

Fields after the marker may have defaults, but they do not have to. A required field remains required; callers simply have to name it.

@dataclass
class Connection:
    host: str
    _: KW_ONLY
    token: str
    port: int = 443
    verify_tls: bool = True

conn = Connection('api.example.com', token='secret')

This is valuable for credentials and security settings. Explicit labels such as token= and verify_tls= reduce mistakes in long calls and make code review easier.

Defaults and constructor design

Keyword-only parameters do not remove the need for good defaults. Defaults should be safe, predictable, and documented. Avoid defaults that perform work, read the environment, or create mutable shared state. Use field(default_factory=...) for lists, dictionaries, and other mutable values.

When a class grows beyond a manageable number of options, split it into smaller configuration dataclasses. KW_ONLY improves a constructor, but it should not be used to justify an object with dozens of unrelated responsibilities.

Inheritance and final field order

Dataclasses merge fields from base and derived classes. Therefore, inheritance can make the final constructor less obvious than the source of one class suggests. A marker in a base class shapes that class, while a subclass can introduce additional fields and its own keyword-only decisions.

Use inspect.signature to verify the public constructor:

from inspect import signature
print(signature(Service))

For a library, a small signature test is useful. It catches accidental changes when fields are reordered or a new base class is introduced.

Pattern matching and __match_args__

Keyword-only fields are not added to __match_args__. As a result, positional structural patterns only include positional dataclass fields. This usually makes matching more stable.

match api:
    case Service(name):
        print(name)

To inspect keyword-only data, match by attribute: case Service(timeout=10). Attribute patterns are explicit and continue to work if internal field ordering changes.

Using dataclasses.replace

dataclasses.replace works naturally with keyword-only fields because modifications are supplied by name. It is especially useful with immutable models declared using frozen=True.

from dataclasses import replace
fast = replace(api, timeout=5)

The function creates a new instance, changes the requested field, and preserves the remaining state. This supports clear, functional updates without mutation.

Why it helps public APIs

Positional parameters are part of a public contract. Adding a parameter in the middle of a positional signature can break or, worse, reinterpret older calls. Keyword-only optional fields are easier to add because callers identify them by name.

This matters in SDKs, internal libraries, domain models, service clients, and configuration objects that evolve over time. Keyword-only fields do not replace semantic versioning, but they reduce the number of changes that require a breaking release.

Validation still matters

KW_ONLY controls how arguments are passed; it does not validate their values. Use __post_init__ for domain rules.

@dataclass
class Job:
    name: str
    _: KW_ONLY
    priority: int = 5
    attempts: int = 3

    def __post_init__(self):
        if not 1 <= self.priority <= 10:
            raise ValueError('priority must be between 1 and 10')
        if self.attempts < 0:
            raise ValueError('attempts cannot be negative')

The constructor remains readable while validation protects the object state. These techniques solve different problems and work well together.

Common mistakes

Do not add multiple KW_ONLY markers to one dataclass. One boundary is enough. Name the marker _ so readers immediately understand that it is not real data. Avoid making every tiny identifier keyword-only when a simple positional call would be natural.

Another mistake is treating keyword-only fields as a security mechanism. They improve clarity but do not sanitize input, enforce types at runtime, or protect secrets. Validation, type checking, and secure storage remain separate concerns.

Testing the contract

Test successful named calls and expected failures for positional calls. Check required keyword-only fields, default values, inheritance, pattern matching, and replace. For public packages, snapshotting the signature can prevent accidental compatibility changes.

Static type checkers also understand keyword-only constructor parameters generated by dataclasses. Running tools such as mypy or Pyright adds another layer of protection before runtime.

Practical design checklist

Keep only one or two truly essential fields positional. Make options and flags keyword-only. Choose safe defaults. Validate domain rules in __post_init__. Prefer smaller composed models over a giant constructor. Document required fields and test the final signature.

For external data validation, a library such as Pydantic may be more appropriate. For lightweight typed records inside Python applications, dataclasses remain an efficient standard-library choice.

Continue with our guides to Python typing.override, Python StrEnum, Python SimpleNamespace, and Python types.new_class. Together, they help you design clearer models and safer contracts.

For primary references, read the official dataclasses documentation and PEP 557.

Conclusion

dataclasses.KW_ONLY is a small feature with a large effect on readability and compatibility. It preserves concise positional arguments where they make sense and requires explicit names for options that could otherwise be confused. In evolving projects, that boundary reduces mistakes, improves reviews, and makes new optional fields easier to introduce. Combine it with validation, signature tests, type checking, and clear documentation for robust dataclass APIs.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Software developer using Python operator.methodcaller
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    operator.methodcaller: Call Methods in Pipelines

    Learn Python operator.methodcaller for map, sorted, callbacks, arguments, reusable transformations, and clearer declarative pipelines.

    Ler mais

    Tempo de leitura: 5 minutos
    07/09/2026
    Open folder representing files and directories in Python
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    pathlib.Path.walk: Traverse and Filter Directories

    Learn how to traverse directories with pathlib.Path.walk in Python, filter files, skip folders, handle errors, and avoid common pitfalls.

    Ler mais

    Tempo de leitura: 5 minutos
    07/09/2026
    Python code validated with enum.verify
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    enum.verify: Validate Enum Rules in Python

    Learn Python enum.verify to validate unique values, continuous sequences, and named flags with explicit enum rules.

    Ler mais

    Tempo de leitura: 6 minutos
    06/09/2026
    Software dependency graph and task workflow with Python TopologicalSorter
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    TopologicalSorter: Order Dependencies Safely

    Learn Python TopologicalSorter to order dependencies, detect cycles, and run sequential or parallel pipelines safely.

    Ler mais

    Tempo de leitura: 6 minutos
    06/09/2026
    Folders and directories representing Python os.fwalk
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python os.fwalk: Traverse Directories

    Learn Python os.fwalk to traverse directories with file descriptors, reduce race conditions, and handle files more safely.

    Ler mais

    Tempo de leitura: 4 minutos
    05/09/2026
    Software developer reviewing Python code and overridden methods
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    typing.override: Validate Method Overrides

    Learn Python typing.override for safer method overrides, compatible signatures, inheritance contracts, and reliable refactoring.

    Ler mais

    Tempo de leitura: 6 minutos
    05/09/2026