File: comparison.md

package info (click to toggle)
python-attrs 25.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,004 kB
  • sloc: python: 10,495; makefile: 153
file content (70 lines) | stat: -rw-r--r-- 2,113 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Comparison

By default, two instances of *attrs* classes are equal if they have the same type and all their fields are equal.
For that, *attrs* writes `__eq__` and `__ne__` methods for you.

Additionally, if you pass `order=True`, *attrs* will also create a complete set of ordering methods: `__le__`, `__lt__`, `__ge__`, and `__gt__`.

For equality, *attrs* will generate a statement comparing the types of both instances,
and then comparing each attribute in turn using `==`.

For order, *attrs* will:

- Check if the types of the instances you're comparing are equal,
- if so, create a tuple of all field values for each instance,
- and finally perform the desired comparison operation on those tuples.

(custom-comparison)=

## Customization

As with other features, you can exclude fields from being involved in comparison operations:

```{doctest}
>>> from attrs import define, field
>>> @define
... class C:
...     x: int
...     y: int = field(eq=False)

>>> C(1, 2) == C(1, 3)
True
```

Additionally you can also pass a *callable* instead of a bool to both *eq* and *order*.
It is then used as a key function like you may know from {func}`sorted`:

```{doctest}
>>> @define
... class S:
...     x: str = field(eq=str.lower)

>>> S("foo") == S("FOO")
True

>>> @define(order=True)
... class C:
...     x: str = field(order=int)

>>> C("10") > C("2")
True
```

This is especially useful when you have fields with objects that have atypical comparison properties.
Common examples of such objects are [NumPy arrays](https://github.com/python-attrs/attrs/issues/435).

To save you unnecessary boilerplate, *attrs* comes with the {func}`attrs.cmp_using` helper to create such functions.
For NumPy arrays it would look like this:

```python
import numpy

@define
class C:
   an_array = field(eq=attrs.cmp_using(eq=numpy.array_equal))
```

:::{warning}
Please note that *eq* and *order* are set *independently*, because *order* is `False` by default in {func}`~attrs.define` (but not in {func}`attr.s`).
You can set both at once by using the *cmp* argument that we've undeprecated just for this use-case.
:::