0
# Field Configuration
1
2
Define attributes with validation, conversion, default values, and metadata using both modern and legacy APIs. Fields provide fine-grained control over attribute behavior, serialization, and validation.
3
4
## Capabilities
5
6
### Modern Field Definition
7
8
#### Field Function
9
Define attributes with comprehensive configuration options for modern attrs classes.
10
11
```python { .api }
12
def field(
13
*,
14
default=NOTHING,
15
factory=None,
16
validator=None,
17
repr=True,
18
hash=None,
19
init=True,
20
metadata=None,
21
converter=None,
22
kw_only=False,
23
eq=True,
24
order=None,
25
on_setattr=None,
26
alias=None,
27
type=None,
28
):
29
"""
30
Define a field for attrs classes with comprehensive configuration.
31
32
Parameters:
33
- default (Any): Default value for the attribute
34
- factory (callable, optional): Function to generate default values
35
- validator (callable or list, optional): Validation function(s)
36
- repr (bool): Include in __repr__ output (default: True)
37
- hash (bool, optional): Include in __hash__ calculation
38
- init (bool): Include in __init__ method (default: True)
39
- metadata (dict, optional): Arbitrary metadata for the field
40
- converter (callable or list, optional): Value conversion function(s)
41
- kw_only (bool): Make this field keyword-only (default: False)
42
- eq (bool): Include in equality comparison (default: True)
43
- order (bool, optional): Include in ordering comparison
44
- on_setattr (callable or list, optional): Hooks for attribute setting
45
- alias (str, optional): Alternative name for the field in __init__
46
- type (type, optional): Type annotation for the field
47
48
Returns:
49
Field descriptor for use in class definitions
50
"""
51
```
52
53
Usage examples:
54
```python
55
@attrs.define
56
class Person:
57
# Simple field with default
58
name: str = attrs.field()
59
60
# Field with validation
61
age: int = attrs.field(validator=attrs.validators.instance_of(int))
62
63
# Field with factory function
64
created_at: datetime = attrs.field(factory=datetime.now)
65
66
# Field excluded from repr
67
password: str = attrs.field(repr=False)
68
69
# Keyword-only field
70
debug: bool = attrs.field(default=False, kw_only=True)
71
72
# Field with converter
73
tags: list = attrs.field(factory=list, converter=list)
74
75
# Field with metadata
76
score: float = attrs.field(
77
default=0.0,
78
metadata={"unit": "points", "min": 0.0, "max": 100.0}
79
)
80
```
81
82
### Legacy Field Definition
83
84
#### Attrib Function
85
Define attributes using the legacy API with comprehensive configuration options.
86
87
```python { .api }
88
def attrib(
89
default=NOTHING,
90
validator=None,
91
repr=True,
92
cmp=None,
93
hash=None,
94
init=True,
95
metadata=None,
96
converter=None,
97
factory=None,
98
kw_only=False,
99
eq=None,
100
order=None,
101
on_setattr=None,
102
alias=None,
103
type=None,
104
):
105
"""
106
Legacy field definition with comprehensive configuration.
107
108
Parameters: Similar to field() but uses cmp instead of eq/order
109
- cmp (bool, optional): Include in comparison methods (deprecated, use eq/order)
110
- Other parameters same as field()
111
112
Returns:
113
Attribute descriptor for use in class definitions
114
"""
115
```
116
117
Usage examples:
118
```python
119
@attr.attrs
120
class Person:
121
name = attr.attrib()
122
age = attr.attrib(validator=attr.validators.instance_of(int))
123
email = attr.attrib(default="")
124
created_at = attr.attrib(factory=datetime.now)
125
```
126
127
### Field Aliases
128
129
Legacy aliases for backward compatibility:
130
131
```python { .api }
132
# In attr module
133
ib = attr = attrib # Field definition aliases
134
```
135
136
### Factory Functions
137
138
#### Factory Class
139
Wrapper for factory functions that generate default values.
140
141
```python { .api }
142
class Factory:
143
"""
144
Wrapper for factory functions used as default values.
145
146
Attributes:
147
- factory (callable): Function to generate default values
148
- takes_self (bool): Whether factory function receives instance as first argument
149
"""
150
151
def __init__(self, factory, takes_self=False):
152
"""
153
Create a factory wrapper.
154
155
Parameters:
156
- factory (callable): Function to call for default values
157
- takes_self (bool): Pass instance as first argument (default: False)
158
"""
159
```
160
161
Usage examples:
162
```python
163
@attrs.define
164
class Record:
165
# Simple factory
166
created_at: datetime = attrs.field(factory=datetime.now)
167
168
# Factory that takes self
169
id: str = attrs.field(factory=Factory(lambda self: f"{self.name}_{uuid.uuid4()}", takes_self=True))
170
name: str = ""
171
172
# Using Factory class directly
173
data: dict = attrs.field(factory=Factory(dict))
174
```
175
176
### Converters
177
178
#### Converter Class
179
Wrapper for converter functions with additional context.
180
181
```python { .api }
182
class Converter:
183
"""
184
Wrapper for converter functions with context information.
185
186
Attributes:
187
- converter (callable): Function to convert values
188
- takes_self (bool): Whether converter receives instance as argument
189
- takes_field (bool): Whether converter receives field info as argument
190
"""
191
192
def __init__(self, converter, *, takes_self=False, takes_field=False):
193
"""
194
Create a converter wrapper.
195
196
Parameters:
197
- converter (callable): Function to convert values
198
- takes_self (bool): Pass instance as argument (default: False)
199
- takes_field (bool): Pass field info as argument (default: False)
200
"""
201
```
202
203
Usage examples:
204
```python
205
def normalize_email(value):
206
return value.lower().strip()
207
208
def context_converter(value, instance, field):
209
return f"{field.name}: {value} (from {instance.__class__.__name__})"
210
211
@attrs.define
212
class User:
213
email: str = attrs.field(converter=normalize_email)
214
name: str = attrs.field(converter=Converter(context_converter, takes_self=True, takes_field=True))
215
```
216
217
### Special Values
218
219
#### NOTHING Constant
220
Sentinel value indicating the absence of a value when None is ambiguous.
221
222
```python { .api }
223
NOTHING: NothingType # Sentinel for missing values
224
225
class NothingType:
226
"""Type for NOTHING literal value."""
227
228
def __bool__(self) -> False:
229
"""NOTHING is always falsy."""
230
```
231
232
Usage example:
233
```python
234
@attrs.define
235
class Config:
236
# Distinguish between None and not set
237
timeout: Optional[int] = attrs.field(default=NOTHING)
238
239
def get_timeout(self) -> int:
240
if self.timeout is NOTHING:
241
return 30 # Default timeout
242
return self.timeout
243
```
244
245
## Common Patterns
246
247
### Validation with Type Hints
248
```python
249
@attrs.define
250
class Point:
251
x: float = attrs.field(validator=attrs.validators.instance_of(float))
252
y: float = attrs.field(validator=attrs.validators.instance_of(float))
253
```
254
255
### Complex Default Values
256
```python
257
@attrs.define
258
class Configuration:
259
# Mutable defaults using factory
260
features: list = attrs.field(factory=list)
261
settings: dict = attrs.field(factory=dict)
262
263
# Computed defaults
264
created_at: datetime = attrs.field(factory=datetime.now)
265
id: str = attrs.field(factory=lambda: str(uuid.uuid4()))
266
```
267
268
### Field Exclusion and Control
269
```python
270
@attrs.define
271
class User:
272
username: str
273
password: str = attrs.field(repr=False) # Hide from repr
274
internal_id: int = attrs.field(init=False, eq=False) # Not in init or comparison
275
276
def __attrs_post_init__(self):
277
self.internal_id = hash(self.username)
278
```
279
280
### Metadata and Introspection
281
```python
282
@attrs.define
283
class APIField:
284
value: str = attrs.field(metadata={"api_name": "fieldValue", "required": True})
285
optional: str = attrs.field(default="", metadata={"api_name": "optionalField", "required": False})
286
287
# Access metadata
288
field_info = attrs.fields(APIField)
289
for field in field_info:
290
if field.metadata.get("required"):
291
print(f"Required field: {field.name}")
292
```
293
294
### Conversion Chains
295
```python
296
@attrs.define
297
class Document:
298
# Convert string to Path object
299
path: Path = attrs.field(converter=Path)
300
301
# Chain converters: strip whitespace, then convert to int
302
priority: int = attrs.field(
303
converter=attrs.converters.pipe(str.strip, int),
304
default="0"
305
)
306
```