# Attrs ```shell pip install attrs ``` attrs gives you a class decorator and a way to declaratively 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