#! Ramblings
of an autodidact...
#! Ramblings
More advanced Dataclass sorting

A useful tip for making your dataclasses more useful

More advanced Dataclass sorting

While checking my email this morning I came across another useful Pybites tip.

dataclass-order

It was a great little tip, but I wondered, "what if I wanted to sort by bite level?"

Pretty up the output

I know it's just an example code, but I like to make my output a bit more readable. A simple loop of the results is all it takes:

for bite in sorted(bites):
    print(bite)

Output:

Bite(number=11, title='Enrich a class', level=<BiteLevel.ADVANCED: 4>)
Bite(number=21, title='Query a nested DS', level=<BiteLevel.BEGINNER: 2>)
Bite(number=25, title='No promo twice', level=<BiteLevel.INTERMEDIATE: 3>)

Ah, much better!

Using a sort_index

As you can see, the bites are being sorted by their number, but I want to see them sorted by difficulty. The first thing I did was add a sort_index to the dataclass and set it to the property that I wanted to sort by, level:

@dataclass(order=True)
class Bite:
    sort_index: int
    number: int
    title: str
    level: int = BiteLevel.BEGINNER

    def __post_init__(self):
        self.sort_index = self.level

Output:

Traceback (most recent call last):
  File "enum_play.py", line 28, in <module>
    Bite(21, "Query a nested DS"),
TypeError: __init__() missing 1 required positional argument: 'title'

Uh oh! Although it's complaining about a missing title, the problem is actually that it's looking for the sort_index.

Dataclasses field(init=False)

I don't want to initialize that variable, so I make the following change to the Bite class:

from dataclasses import dataclass, field
...

class Bite:
    sort_index: int = field(init=False)
    number: int
    ...

We first import field from dataclasses and then set it to init=False in order to prevent that variable from being initialized.

Bite(sort_index=<BiteLevel.BEGINNER: 2>, number=21, title='Query a nested DS', level=<BiteLevel.BEGINNER: 2>)
Bite(sort_index=<BiteLevel.INTERMEDIATE: 3>, number=25, title='No promo twice', level=<BiteLevel.INTERMEDIATE: 3>)
Bite(sort_index=<BiteLevel.ADVANCED: 4>, number=11, title='Enrich a class', level=<BiteLevel.ADVANCED: 4>)

Um, ok better but I don't want to see sort_index being displayed in the output.

Dataclasses field(repr=False)

In order to prevent sort_index from being displayed, we will have to set the repr to False.

class Bite:
    sort_index: int = field(init=False, repr=False)
    ...

Output:

Bite(number=21, title='Query a nested DS', level=<BiteLevel.BEGINNER: 2>)
Bite(number=25, title='No promo twice', level=<BiteLevel.INTERMEDIATE: 3>)
Bite(number=11, title='Enrich a class', level=<BiteLevel.ADVANCED: 4>)

Much better!

Dataclasses frozen

Looking much better! But what if I wanted to make the dataclass so that it could not be changed in the code? That's where frozen comes in:

@dataclass(order=True, frozen=True)
class Bite:
    sort_index: int = field(init=False, repr=False)
    ...

Output:

Traceback (most recent call last):
  File "enum_play.py", line 25, in <module>
    Bite(11, "Enrich a class", BiteLevel.ADVANCED),
  File "<string>", line 6, in __init__
  File "enum_play.py", line 21, in __post_init__
    self.sort_index = self.level
  File "<string>", line 4, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'sort_index'

Ugh, well at least we know it works!

Setting class variables with setattr

It's complaining because we are setting the index_value in __post_init__. In order to get around it, we'll have to set that value a different way.

...

    def __post_init__(self):
        object.__setattr__(self, "sort_index", self.level)

Output:

Bite(number=21, title='Query a nested DS', level=<BiteLevel.BEGINNER: 2>)
Bite(number=25, title='No promo twice', level=<BiteLevel.INTERMEDIATE: 3>)
Bite(number=11, title='Enrich a class', level=<BiteLevel.ADVANCED: 4>)

There we go!

Conclusion

As you can see, working with dataclasses isn't that hard at all and will save you from having to type too much boilerplate code.

Final code:

from dataclasses import dataclass, field
from enum import IntEnum


class BiteLevel(IntEnum):
    BEGINNER = 2
    INTERMEDIATE = 3
    ADVANCED = 4


@dataclass(order=True, frozen=True)
class Bite:
    sort_index: int = field(init=False, repr=False)
    number: int
    title: str
    level: int = BiteLevel.BEGINNER

    def __post_init__(self):
        object.__setattr__(self, "sort_index", self.level)


bites = [
    Bite(11, "Enrich a class", BiteLevel.ADVANCED),
    Bite(21, "Query a nested DS"),
    Bite(25, "No promo twice", BiteLevel.INTERMEDIATE),
]

for bite in sorted(bites):
    print(bite)

If you would like to learn more about Dataclasses, check out the documentation.


Troubleshooting Connectivity Issues

Had issues connecting to FTP server running on Windows 10

Troubleshooting Connectivity Issues My son likes to live stream on Youtube and was in the middle of one the other day when his phone ran out of space. He asked me to backup his images and videos for him so that he could make some room. Some Background I've been an avid Linux user for ages so I've gotten used to not having to use iTunes. I recently made the move back to Windows 10, but I detest having to...

Read More


Benchmarking Python Code

How much faster is one implementation compared to another?

Need to compare which code is faster, read on to find out how A friend of mine, Mridu Bhatnagar, has been posting some really cool articles explaining how she's gone about solving some LeetCode challenges. They are all interesting, but due to time constraints, I have only attempted to see if I can do a couple of them. Move Zeroes One of the first that I attempted to do was Move Zeroes. I thought that I was...

Read More


Advanced type annotations

Some concrete examples on how to type hint more advanced class objects

How to add type annotations to Python dataclasses During the COVID19 outbreak, a lof of companies are either giving away free books, tutorials, or access their training material. One such company is Pluralsight. For the whole month of April 2020, they have given everyone free access to their complete library! The content is just awesome, some of the best I've seen. I have been working through their Python - Beyond the Basics when I came across their section on...

Read More


Cleaning up Anaconda environment.yml files

Cleaning up Anaconda exported environment files is pretty tedious work

Recreating virtual environments with Anaconda I love working with Anaconda. It makes things so much easier. I enjoy using it so much that I even wrote a guest post article on PyBit.es about my workflow. It goes into much more detail on the subject, but I'll cover a few basics here. With that being the case, there is one aspect of it that I really hate and that is creating the environment.yml project file for distribution. Table of Contents What...

Read More


Bash script into a Makefile

How to convert a bash script into a Makefile

Using make can literally make your life easier So the other day on the Pybites slack channel, Erik O'Shaughnessy and I were chatting about something and I happened to mention that I had written a bash script to generate documents from Asciidoc files but wanted to create a Makefile to do the same instead. Without hesitation, he asked for my bash script and got to work! I don't think that I could have found a better tutorial...

Read More


Testing ABC's with abstract methods with Pytest

What I had to do to get 100% coverage on my tests

So you want to test ABC's with pytest I was working on writing a new code challenge for Codechalleng.es the other day. It's based on inheritance and composition and uses Abstract Base Classes to define the interfaces that should be implemented in classes derived from it. I was just finishing up with the tests and everything was passing. Then when I checked the code coverage on it, I saw that it was complaining about my Site...

Read More


Playing around with Jupyter notebooks

Just giving the notebook plugin a test run to see how things render

Seeing how notebooks compare to just plain Markdown¶ What is a Jupyter Notebook¶Well it's a document that lets you render markdown code, display code blocks, and also allows you to execute those code blocks and display their results interactively! Needless to say, they are definitely game changers. It's like the Python interpreter...

Read More


MongoDB CLI Intro

Quick introduction on how to connect to a mondoDB database through the built in mongo cli application

Why another article on MongoDB After publishing my article on How to install MongoDB on Linux I realized that I should have covered how to access it through the command line! Didn't occur to me that anyone reading it might not want to download and install Robo 3T! Sorry about that! Intro into the mongo cli app It's simple enough. Now I'm no expert but this is what I discovered just playing around with it. (base) ➜...

Read More


How to install MongoDB on Linux

How to prepare to start working with MongoDB

Learning about MongoDB So the other day I started going through Michael Kennedy's free MongoDB Quickstart course. Although he covered the Python code portions, he left getting everything setup, up to you. If you're on a Linux machine that uses APT, then keep on reading. Getting MongoDB I could have gone over to MongoDB's download page, and selected the correct version for my setup, but I wanted to stick with the package manager on my machine. The latest version...

Read More


  • 1
  • 2

Receive Updates

ATOM