Blog

Python Auto Formatter: Autopep8 vs. Black | Built In

Autopep8 and Black are both great tools to auto format your Python code to conform to the PEP 8 style guide. Black is the most popular tool of its kind based on GitHub activity , while autopep8 is slightly less popular .

One of the major differences is that Black is an opinionated formatter, meaning that it always converts the entire codebase into its own style, whereas autopep8 preserves the input style to some extent and only fixes the necessary parts. Data Board

Python Auto Formatter: Autopep8 vs. Black | Built In

I’ve used both tools, and I’d like to share with you why I prefer Black over autopep8.

Autopep8 is a Python tool that automatically formats code to match the PEP 8 style guide. It differs from the auto formatter Black in that it only removes the necessary parts of code that aren’t aligned with PEP 8. 

More on Python __new__ vs. __init__ Methods in Python

Don’t get me wrong, autopep8 is a great tool, and I like it. The best thing about autopep8 is that it allows plenty of user configurations, whereas Black barely allows any. However, I’ve come across some problems with autopep8 that are enough to keep me from using it.

Some may see this as a good thing, however, a good tool should focus on only one thing. As a formatting tool, it shouldn’t try to change the order of the code, and it can sometimes cause problems when it does.

Let’s consider the below example. Although sys.path.append is generally not good practice, let’s say we really want to do something first before importing the rest of the modules.

Autopep8 would rewrite the script into the following:

And this is problematic. In another example, let’s say we want to enable the back end of matplotlib for a Linux terminal . We would need to set the back end matplotlib.use("agg") before the pyplot import from matplotlib import pyplot as plt.

In contrast, Black will not change the example code above. Black only does formatting while the semantics of the code remain exactly the same. In other words, it doesn’t sort your imports and doesn’t change the order of your code. We can leave the task of sorting imports for another great tool, isort .

You can add # nopep8 to solve this issue to some snippets of your code, which explicitly tells autopep8 not to touch it:

It works in this case, but I found that the # nopep8 exclusion rule is not applied to comments. So, autopep8 would still convert the following ### some comment # nopep8 into # some comment # nopep8.

On the other hand, Black does not edit comments and docstrings, and you can exclude some of your code from being formatted by adding two comment lines # fmt: off and # fmt: on before and after your code block.

Anyway, it’s not very Pythonic , right?

Autopep8’s default indentation is set to the same as your editor’s tab size, and you can specify the value with the --indent-size argument. Autopep8 only uses this input value to set the indentation for the beginning of each statement, but the indentation within brackets is always set to the default tab size.

Let’s look at this example, where the code indentation is one, and my editor’s default tab size is four.

After setting indentation to three with autopep8 autopep8 --indent-size 3 -i format_02_raw.py ( -i means in place), we get the following:

We can see that the indentation in the first function is set correctly to three, but everything within brackets, in this case, the print statement and the matrix, are set to the default tab size of four.

I found this out because the default tab size in my work environment is two, and I prefer the indentation of four. It might sound trivial, but why risk the unnecessary inconsistency? Black doesn’t allow you to configure the indent size, as it always sets indentation to four in all places, which I don’t mind at all.

Black is an auto formatting tool for Python that edits code to align it with the PEP 8 style guide. It differs from autopep8 in that it formats the entire codebase to its own style.

Black implements its own style, which some people like and some people don’t. I like it as it’s generally very clean and readable, but there are two things to keep in mind.

The examples below show one of the most common reasons why some people don’t like Black. Here’s what the code looks like before formatting:

After formatting, without trailing commas:

It’s annoying, but before you get mad, let’s make some small changes to the code and see how Black changes its behavior. Here it is before formatting, with trailing commas:

After formatting, with trailing commas:

Yes, Black uses trailing commas to decide whether the items will be wrapped together or stay in new lines. If an array-like item ends without a trailing comma, whether it’s a list, matrix or dictionary, black always tries to warp it into one line. If it exceeds the length of the line, black then puts its contents in new lines and adds a trailing comma for you. If there is a trailing comma in the item, black makes sure its contents are separated into new lines.

In short, there will always be a trailing comma wherever an array-like item’s contents are in new lines. This makes sense, and in general, trailing commas are good practice as they make the code easier to maintain, as well as generate clean git diff when you make changes. So, if you don’t want black to wrap your code into one line, add a comma at the end.

Bonus tips: when I write SQL queries , I would write:

I do that for the same reasons. It makes it easier to add or delete items and makes the code easier to maintain.

The only thing I don’t like about the Black code style so far is regarding long if-statements, as the below example shows. Here it is before formatting:

It enforced consistency but sacrificed readability. Black’s default line length is 88, but sometimes I do have slightly longer statements, and I don’t want them to be formatted that way.

My solution is to allow a slightly longer line length. We can specify the line length using the --line-length or -l argument, and if we set the line length to 100, black -l 100 format_05_raw.py, the above example will not be reformatted. From my experience, a 100-ish line length would suit most long statements while still retaining good code readability. Although, you should really consider rewriting your statement if it’s over 100 characters long. Of course, this is up to each team to decide.

Autopep8 also has such an option --max-line-length, however, as autotpep8 tends to preserve the original code style, the formatting result is much less sensitive to the specified line length than black.

Black doesn’t sort your imports, but we can use isort  to do this. Let’s look at a quick example of what isort can do. Here is the code before isort:

It’s neat, and it doesn’t mess up our sys.path.append example.

There are some slight differences between how isort and Black organize imports, and we can set isort’s --profile option to black to sort the imports conforming to the Black code style, isort --profile black format_06_raw.py; we can also specify the line length with the -l argument.

We now have a pretty good workflow: use isort to sort the imports first, and then use Black to format the code. We can combine the two steps together in Makefile:

And now we can simply use make format to achieve everything discussed above (on an imaginary src/ folder).

More on Python 5 Ways to List Files in Python Directory

Here’s the conclusion: I prefer Black over autopep8, but there are some practical tips that you should keep in mind when using Black, and it works best in parallel with some other tools like isort.

Python Auto Formatter: Autopep8 vs. Black | Built In

Cotton Oil Application Pad Built In’s expert contributor network publishes thoughtful, solutions-oriented stories written by innovative tech professionals. It is the tech industry’s definitive destination for sharing compelling, first-person accounts of problem-solving on the road to innovation.