Indentation

So, while digging around in some external library code I stumbled across this method:

def format(self, value):
    if isinstance(value, set):
        value = list(value)

    return [
        self.container.output(idx,
            val if (isinstance(val, dict)
                    or (self.container.attribute
                        and hasattr(val, self.container.attribute)))
                    and not isinstance(self.container, Nested)
                    and not type(self.container) is Raw
                else value)
        for idx, val in enumerate(value)
    ]

You can see it is very difficult to understand what is going on there.. Please do not try to understand what the method is doing or where it comes from. That’s not the point I am trying to make here - just look inside self.container.output.

The method self.container.output gets the parameter idx and either val or value based on some conditions. These conditions are the cause why it is hard to understand. It is val if three conditions are met, but the first one contains further nested conditions where one of them is again nested… Complicated.

So I took the liberty to reformat the code without changing the logic of it (just whitespace changes). It turned out to this:

def format(self, value):
    if isinstance(value, set):
        value = list(value)

    return [
        self.container.output(
            idx,
            val
            if (
                isinstance(val, dict)
                or (
                    self.container.attribute
                    and hasattr(val, self.container.attribute)
                )
            )
            and not isinstance(self.container, Nested)
            and not type(self.container) is Raw
            else value
        )
        for idx, val in enumerate(value)
    ]

Well, yes, it became much longer, but on the pro side my PEP8 linter in the editor won’t complain about bad-continuation anymore. (It still complains about the Redefining built-in ‘format’, but anyway…)

Basically I removed all the hanging indents - now it is much easier to understand how these conditions interact. That single or moved one indentation step further to the right, so one can clearly see, it has nothing to do with the ands on the outside.


Then I remembered some talk I watched years ago - If your code is easy to grasp visually, the chance someone else understands it is way higher.

Ok, let’s give it a try - how about some dirty script?

#!/usr/bin/env python3

from sys import stdin, stdout
from string import whitespace

if __name__ == '__main__':
    for line in stdin:
        stdout.write(''.join(
            char if char in whitespace else '#' for char in line
        ))

    stdout.flush()

It replaces everything but whitespace with an # character.

The first example turns out like this:

### ############ #######
    ## ################# #####
        ##### # ###########

    ###### #
        ##########################
            ### ## ################ #####
                    ## #########################
                        ### ############ ###########################
                    ### ### ########################## #######
                    ### ### #################### ## ###
                #### ######
        ### #### ### ## ################
    #

And the second one like this:

### ############ #######
    ## ################# #####
        ##### # ###########

    ###### #
        ######################
            ####
            ###
            ## #
                ############### #####
                ## #
                    ########################
                    ### ############ #########################
                #
            #
            ### ### ########################## #######
            ### ### #################### ## ###
            #### #####
        #
        ### #### ### ## ################
    #

Just by looking at these outputs without comparing it to the original code (don’t scroll up) it is suddenly possible to see the different nesting levels, and how they act together.

In my opinion, the second one shows it more clearly - although it takes up much more horizontal space. But I think this is worth it - scrolling through text on the screen takes much less effort than reading the same code over and over again…

Think of it next time you are trying to write very dense code!

So long!