Code Yarns ‍👨‍💻
Tech BlogPersonal Blog

attrs package in Python

📅 2016-Sep-07 ⬩ ✍️ Ashwin Nanjappa ⬩ 🏷️ attrs, dataclasses, python ⬩ 📚 Archive

It is very rare that you learn something that completely changes how you program. Reading this post about the attrs package in Python was a revelation to me.

Coming from C++, I am not too big a fan on returning everything as lists and tuples. In many cases, you want to have structure and attributes and the class in Python is a good fit for this. However, creating a proper class with attributes that has all the necessary basic methods is a pain.

This is where attrs comes in. Add its decorator to the class and designate the attributes of the class using its methods and it will generate all the necessary dunder methods for you. You can also get some nice type checking and default values for the attributes too.

$ python3 -m pip install attrs
@attr.s
class Creature:
    eyes = attr.ib()
    legs = attr.ib()
c = Creature(2, 4)
c = Creature(legs=6, eyes=1000)
c = Creature()

TypeError: __init__() missing 2 required positional arguments: 'eyes' and 'legs'
@attr.s
class Creature:
    eyes = attr.ib(default=2)
    legs = attr.ib(default=6)

c = Creature()

Note that if there are some rules you run up against if you provide default values for some attributes and not to others.

c = Creature(3, 6)
print(c)

Creature(eyes=3, legs=6)

This is for me the killer feature! This is far more informational than just looking at a bunch of list or dict values.

c = Creature(2, 4)
c.eyes = 10
print(c.legs)
c1 = Creature(2, 4)
c2 = Creature(3, 9)
c1 == c2
@attr.s
class Creature:
    eyes = attr.ib(validator=attr.validators.instance_of(int))
    legs = attr.ib()

c = Creature(3.14, 6)

TypeError: ("'eyes' must be <class 'int'> (got 3.14 that is a <class 'float'>)."
@attr.s(slots=True)
class Creature:
    eyes = attr.ib()
    legs = attr.ib()
import inspect
print(inspect.getsource(Creature.__init__))
print(inspect.getsource(Creature.__eq__))
print(inspect.getsource(Creature.__gt__))
print(attr.fields(Creature))

(Attribute(name='eyes', default=NOTHING, validator=<instance_of validator for type <class 'int'>>, repr=True, cmp=True, hash=True, init=True, convert=None), Attribute(name='legs', default=NOTHING, validator=None, repr=True, cmp=True, hash=True, init=True, convert=None))

There is a lot more stuff in this awesome must-use package that can be read here

Update: dataclasses were introduced in Python 3.7 and they seem to have a lot of features of attrs.

Tried with: attrs 16.1.0, Python 3.5.2 and Ubuntu 16.04


© 2023 Ashwin Nanjappa • All writing under CC BY-SA license • 🐘 Mastodon📧 Email