attrs Library — Core Concepts

attrs is a Python library that generates special methods (__init__, __repr__, __eq__, __hash__, and more) for your classes based on field declarations. It was created in 2015 by Hynek Schlawack and directly inspired Python’s built-in dataclasses module (added in 3.7). While dataclasses cover the basics, attrs provides a superset of features that matter in production code.

Why attrs over dataclasses

Python’s dataclasses are deliberately limited — they handle the 80% case. attrs fills the remaining 20%:

  • Validators: Built-in support for field validation at instantiation time. Dataclasses have no validation mechanism.
  • Converters: Automatic type conversion when setting fields. Pass a string where an int is expected, and attrs can convert it.
  • Slots by default: attrs can generate __slots__ classes, reducing memory usage by 40-50% per instance.
  • Frozen classes: True immutability through __slots__ + frozen, not just a FrozenInstanceError on __setattr__.
  • Aliases and renaming: Field names in __init__ can differ from attribute names.

Defining an attrs class

The modern API uses @attrs.define (or @attr.s in the classic API):

import attrs

@attrs.define
class Coordinate:
    x: float
    y: float
    label: str = "origin"

This generates __init__, __repr__, __eq__, and uses __slots__ by default. The class is mutable unless you add frozen=True.

Validators

Validators run during __init__ and optionally on __setattr__. attrs ships common validators and supports custom ones:

Built-in validators include instance_of, in_, matches_re, min_len, max_len, gt, lt, ge, le, and and_ (for combining multiple validators). You can also write a plain function that takes instance, attribute, and value and raises ValueError on bad input.

Validators prevent bad data from ever existing as an object. Unlike external validation (check data, then create object), attrs validates during construction — there is no window where an invalid object can circulate.

Converters

Converters transform input values before validation runs. A converter is any callable that takes the raw value and returns the converted one. For example, you can set a converter that wraps an input string as a Path object automatically.

The order is: converter runs first, then validator. This means you can accept flexible input types while still enforcing strict invariants on the result.

Frozen (immutable) classes

Adding frozen=True to the decorator makes instances immutable. Any attempt to set an attribute after creation raises FrozenInstanceError. Combined with __slots__, frozen attrs classes are true value objects — safe to use as dictionary keys, set members, or cache keys.

Common misconception

Many developers think attrs is obsolete because dataclasses exist. In reality, dataclasses were inspired by attrs and intentionally left out validators, converters, and several other features. The attrs maintainer sits on the Python core team and the two libraries are complementary. Use dataclasses for simple containers; use attrs when you need the extra power.

Ecosystem integration

attrs classes work seamlessly with type checkers (mypy, pyright), serialization libraries (cattrs for structured conversion), and testing tools (Hypothesis can auto-generate attrs instances). The evolve() function creates modified copies of frozen instances without mutation.

One thing to remember: attrs gives you everything dataclasses offer plus validators, converters, and true immutability — making it the go-to choice for data classes that need to enforce invariants.

pythonattrsclassesdata-modeling

See Also