# Attrs
```shell
pip install attrs
```
attrs gives you a class decorator and a way to declaratively [[Definition|define]] the attributes on that class:
```python
>>> from attrs import asdict, define, make_class, Factory
>>> @define
... class SomeClass:
... a_number: int = 42
... list_of_numbers: list[int] = Factory(list)
...
... def hard_math(self, another_number):
... return self.a_number + sum(self.list_of_numbers) * another_number
>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
>>> sc.hard_math(3)
19
>>> sc == SomeClass(1, [1, 2, 3])
True
>>> sc != SomeClass(2, [3, 2, 1])
True
>>> asdict(sc)
{'a_number': 1, 'list_of_numbers': [1, 2, 3]}
>>> SomeClass()
SomeClass(a_number=42, list_of_numbers=[])
>>> C = make_class("C", ["a", "b"])
>>> C("foo", "bar")
C(a='foo', b='bar')
```
After declaring your attributes, attrs gives you:
- a concise and explicit overview of the class's attributes,
- a nice human-readable **repr**,
- equality-checking methods, an initializer,
- and much more,
without writing dull boilerplate code again and again and without runtime performance penalties.
## Legacy
You may have encountered code similar to this:
```python
@attr.s
class Point:
x = attr.ib()
y = attr.ib()
```
This is an old way of declaring classes with attrs.[^1] `attr.s` and `attr.ib` should be read `attrs` and `attrib`. Those names won’t be removed from attr, you can still use it, there is no need to update all the codebase for this.
---
Bibliography:
- [attrs - pypi.org](https://pypi.org/project/attrs/)
- [attrs: Classes Without Boilerplate - attrs.org](https://www.attrs.org/en/latest/index.html)
[^1]: https://www.attrs.org/en/latest/names.html