Python Attrs: Advanced Data Classes, With Example Code • Python Land Tips & Tricks (original) (raw)

The package Python Attrs allows you to create advanced data classes using simple annotations. Of course, python has its own native data class module as well, but the Python attrs package offers a couple of extra features you might like!

Table of Contents

Install attrs

The attrs package is not part of the base library, so you will need to install it with the pip install command or something similar, like Pipenv. You probably also want to create a virtual environment, so it won’t interfere with other projects you have. The package is called attrs, so installing it will look like this:

$ pip install attrs

or with pipenv:

$ pipenv install attrs

The authors of attrs have, in fact, worked on the PEP that introduced data classes into Python. Python’s native data classes are intentionally kept simpler and easier to understand while attrs offering the full range of features you might want!

Some of the reasons to choose Python attrs over the built-in data classes are:

A basic Python attrs example

Let’s look at a very basic example first:

`import attr

@attr.s class Person(object): name = attr.ib(default='John') surname = attr.ib(default='Doe') age = attr.ib(init=False)

p = Person() print(p) p = Person('Bill', 'Gates') p.age = 60 print(p)

Output:

Person(name='John', surname='Doe', age=NOTHING)

Person(name='Bill', surname='Gates', age=60)`Code language: Python (python)

A couple of observations:

Next let’s look at the most important features this package offers over regular data classes: validators and converters.

Python attrs validator example

You can add validators to your attrs data class in two ways:

  1. Using a decorator
  2. By providing a callable function

I’ll demonstrate the callable function method here first. Attrs offers several validators out of the box, of which we’ll use the instance_of validator in the following example:

`>>> @attr.s ... class C(object): ... x = attr.ib(validator=attr.validators.instance_of(int))

C(42) C(x=42) C("a string")

Traceback (most recent call last): ... TypeError: ("'x' must be <type 'int'> (got 'a string' that is a <type 'str'>).", ...`Code language: Python (python)

Since we tried to create an object C with a string value for x, the instance_of validator throws an error because it requires an int type instead of a string.

Let’s now define our own validator:

`import attr

@attr.s class DividableByTwo(object): x = attr.ib()

@x.validator
def check(self, attribute, value):
    if value % 2 != 0:
        raise ValueError(f'{value} is not dividable by 2')

print (DividableByTwo(60)) print (DividableByTwo(11))

Output will be something like:

DividableByTwo(x=60)

...

ValueError: 11 is not dividable by 2`Code language: Python (python)

Python attrs converter example

A converter takes the value that is set and converts it automatically. You can use this for all kinds of purposes. One example is to automatically convert a value to an int. Again, let’s start with using a callable function, in this case, we simply use Python’s int() function:

`import attr

@attr.s class C(object): x = attr.ib(converter=int)

c = C("1") print(c)

Output:

C(x=1)`Code language: Python (python)

Our input (the string “1”) was converted to an integer automatically. Because converters are run before validators, you can validate the final value after conversion. E.g., you could combine the above two examples to first convert any input to int, and then check if the value is dividable by two.

Using slots with Python attrs

Finally, you can tell attrs to use slotted classes. Slotted classes have some advantages over regular classes:

In short, with a slotted class you explicitly state which instance attributes you expect your object instances to have. This way, Python can leave out some checks and such, resulting in less memory usage and slight speed increases. You can find more details in the attrs documentation here.

However, slotted classes come with caveats too, especially when you manually create them. Luckily, attrs offers us a simple way to enable the feature:

import attr

@attr.s(slots=True) class YourClassName: ...

Keep learning

Learn Python properly through small, easy-to-digest lessons, progress tracking, quizzes to test your knowledge, and practice sessions. Each course will earn you a downloadable course certificate.