In theory, any Python code is OK as long as it’s syntactically correct and runs as intended. In practice, you want to adopt a consistent style across your projects, preferably one guided by Python’s own style recommendations. The good news is you don’t have to do this by hand. The Python ecosystem contains a variety of tooling, from the highly focused to the wide-ranging, to ensure that Python source code adheres to style conventions.
In this article we’ll examine four popular tools for checking Python code styles, plus one for reformatting code to be consistent. Python IDEs like PyCharm or Visual Studio Code support them either natively or with an extension, so they can be readily integrated into your development workflow.
Pycodestyle
PEP 8 is the document that spells out Python’s coding conventions — everything from whether to use tabs or spaces when indenting (use four spaces, problem solved) to how to name variables and objects. Pycodestyle is the Python module that checks Python code against the PEP 8 recommendations and delivers a report on where the analyzed code is out of spec.
Pycodestyle doesn’t provide automatic fixes for issues; that’s on you. But Pycodestyle is highly configurable, allowing you to suppress specific kinds of errors or parse only specific files in a source tree. And just about every IDE with Python support also supports Pycodestyle, so it’s the easy choice for universal compatibility, if not functionality.
Many Python code linters can work as modules in Python, and Pycodestyle is no exception. You can use it to verify code programmatically, for instance as part of a test suite.
Best for: Basic verification of PEP 8 conformance.
Autopep8
Autopep8 picks up where Pycodestyle leaves off. It uses Pycodestyle to determine what changes need to be made, then reformats code to conform to the suggestions provided. Existing files can be reformatted in place or written to new files. Autopep8 also fixes a host of other issues that can creep in, such as cleaning up code converted from Python 2 to Python 3 or files that have mixed line-ending markers. And Autoprep8 can be used programmatically to reformat code supplied as strings.
Best for: Converting files to be PEP-8 conformant.
Flake8
Flake8 wraps up several Python linting and code-style tools in a single package. Along with PyFlakes, which uses syntax checking to detect basic errors, and Pycodestyle, which we discussed above, Flake8 provides an additional tool to check the “cyclomatic complexity” of a project — that is, the number of independent code paths found in the program. (Cyclomatic complexity is a potentially useful metric if you want to keep a basic module from becoming too un-basic, for example.) At the end of each analysis, Flake8 delivers a percentile metric for the overall quality of the analyzed code, a handy way to get quick idea of which parts of a codebase are most problematic.
Flake8 also has a plug-in system, so linting can be coupled with git
commits or other automated actions — for instance, to feed problematic code to a reformatter.
Best for: Assessing overall code quality, with specific recommendations.
Pylint
Pylint is probably the most broadly used and supported Python linter out there. Like the others, it looks for errors and deviations from coding standards in your Python code, and offers changes for how to fix those mistakes.
Pylint is also arguably the most completist of the code checkers, in the sense that it can warn you about a great many issues with your code, some of which might not even be relevant in your particular context. The results can be verbose, but can also be tailored to suit the quirks of a particular project.
Pylint looks for five progressively more problematic classes of issues. “Conventions” are violations of PEP 8 or other rules of consistency in Python. “Refactors” indicate code smells, common mistakes, or code that could be reworked to be more efficient or less confusing, such as cyclic imports or files with too many similar lines that could be condensed into a common function. “Warnings” are Python-specific issues, like unreachable code (everything after a return
in a function) or classes missing an __init__
method. “Errors” are actual code bugs, like undefined variables, and “Fatal” problems are those that prevent Pylint from even running.
Again, what makes Pylint both most useful and most heavyweight is the amount of feedback it gives. The good news is that for those who want to tune it, Pylint’s verbosity and granularity can be modified per-project or even per-file. Plus, you can draw on a range of Pylint plug-ins that add specific kinds of checks, such as for code that is too complex (long chains of if
s, etc.) or linting for deprecated built-ins.
Best for: Soup-to-nuts quality control for code, assuming you don’t mind tweaking its settings to avoid overload.
Black
Black isn’t a linter or code analysis tool, but a tool for enforcing style as a way to ensure better code quality. For that reason it sits comfortably alongside the other tools described here, since it’s a way to pre-emptively avoid many basic style errors.
Black is described as “the uncompromising code formatter” — uncompromising because it has no settable options except for line length. Black reformats Python code into a singular, consistent, and readable style, drawing on internal rules for handling tricky problems like multiline expressions, so even those get reformatted consistently.
One touted advantage to using Black is that it solves all disputes over formatting, so eliminates “bikeshedding” and makes linter output less noisy, too. You don’t have to argue about how to format code for a project, or even do much of it manually. You just use Black and be done with it; you can even configure many IDEs to automatically format code with Black. Another claimed advantage is that it makes git
commits cleaner, since it reduces the number of changes that get made to any given file.
Best for: Whipping codebases into basic stylistic conformance en masse.
How to do more with Python:
- How to work with the Python list data type
- How to package Python apps with BeeWare Briefcase
- How to run Anaconda side by side with other Pythons
- How to use Python dataclasses
- Get started with async in Python
- How to use asyncio in Python
- 3 steps to a Python async overhaul
- How to use PyInstaller to create Python executables
- Cython tutorial: How to speed up Python
- How to install Python the smart way
- How to manage Python projects with Poetry
- How to manage Python projects with Pipenv
- Virtualenv and venv: Python virtual environments explained
- Python virtualenv and venv do’s and don’ts
- Python threading and subprocesses explained
- How to use the Python debugger
- How to use timeit to profile Python code
- How to use cProfile to profile Python code
- How to convert Python to JavaScript (and back again)