PEP8 - Best practices in styling for Python programming

Recently, I had to go back to some code from my master’s degree. I realized the code was bad written and hard to read. In order to solve this problem, I decided to study what are considered the best styling practices when coding in Python. This post is therefore kind of a cheatsheet for future reference. I intend to keep updating this page as I progress my research in that matter. I used the PEP 8 from the official website python.org as resource. The PEPs, Python Enhancement Proposals, are documents created with the purpose of instructing Python users regarding standards, new features, processes or environments [1]. Specifically, PEP 8 points out the style standards for Python users, in order to the code to be easily readable [2]. So, here we go!

(The code was copied and pasted from [2] although the commments and explanation may be different)

Table of Contents

Code layout

Indentation

Standard: 4 spaces per indentation level

Some possible ways to write:

# Opening delimiter alignment "(".
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Addition of 4 spaces (an extra level of indentation) to distinguish arguments from the rest.
def long_function_name(
        var_one, var_two, var_three,
        var_four):
    print(var_one)

# Hanging indents should add a level.
foo = long_function_name(
    var_one, var_two,
    var_three, var_four)

However, in some cases, you may choose which option is more adequate to the situation:

# Wrong. Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)
# Correct.
def long_function_name(var_one, var_two, 
                        var_three, var_four):
    print(var_one)
Indentation: if-statement

When the conditional part of an if-statement is too long, there may be a problem when breaking it into multiple lines:

if (this_is_one_thing and
    that_is_another_thing):
    do_something()

It is not possible to distinguish the statement and its content exactly because if ( contains four characters. Two possible options are:

# Add a comment between lines.
if (this_is_one_thing and
    that_is_another_thing):
    # Since both conditions are true, we can frobnicate.
    do_something()

# Add some extra indentation on the conditional continuation line.
if (this_is_one_thing
        and that_is_another_thing):
    do_something()
Indentation: brace/bracket/parenthesis

The brace/bracket/parenthesis on multiline constructs should line up with the first non-whitespace character of the last line of the list:

my_list = [
    1, 2, 3,
    4, 5, 6,
    ]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
    )

or align with the first character of the line that starts the multiline construct:

my_list = [
    1, 2, 3,
    4, 5, 6,
]
result = some_function_that_takes_arguments(
    'a', 'b', 'c',
    'd', 'e', 'f',
)

Space or tab?

Standard: spaces are preferred over tabs.

If a code’s indentation default method is tab, you can use tab to match the current style. However, when starting a project, spaces (four) all the way!

Maximum line length

Standard: 79 characters maximum line width. For docstrings and comments, the maximum width should be up to 72 characters.

I thought it was a little strange to limit line width up to 79 characters, but PEP 8 gives two good reasons for choosing this threshold (besides standardization):

  • This length may allow opening two codes side by side, which, in turn, is useful when reviewing them for example;
  • Some text editors have default wrapping of up to 80 characters horizontally. Sizes bigger than that may disrupt the code visual structure, making it harder to read. Therefore, the maximum line width of 79 characters is a safe limit (by one character).

However, for teams that prefer longer lines, and are working in a code exclusively/primarly maintained by them, if a consensus is established, there is no problem in increasing the line width up to 99 characters.

To help standardization, Jupyter Noteboook Extensions offer a tool called ruler that displays a vertical line indicating the character threshold as specified by the user. The figure below shows a piece of my code and the ruler tool enabled.

Code example with the ruler tool from Jupyter Notebook Extensions.

In order to break lines, it is recommended to encapsulate the expressions inside parenthesis, braces or brackets. When this option is not available, it is possible to use backslashes to break lines (although this is the least preferable option). For instance, when declaring a with or assert statement, implicit continuation is not possible, then we can use backslashes

with open('/path/to/some/file/you/want/to/read') as file_1, \
     open('/path/to/some/file/being/written', 'w') as file_2:
    file_2.write(file_1.read())

Binary operators and line breaks

Standard: write binary operators in the beginning of each line.

income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

By doing so, it is possible to better understand the relation between variables. In the case shown above, we can see there are quantities that are added, which indicates some kind of credit, whereas other variables are subtracted, indicating a debt. The operator’s position being in the beginning of the line is therefore convenient since the operation performed (and, thus, its meaning) is explicitly displayed. Also, all operators are aligned, improving readability.

Blank lines

Standard:

  • Class and function definitions start with two blank lines;

  • Method definitions inside classes are surrounded by one blank line;

  • Blank lines can be used to separate groups of related functions;

  • Blank lines can be used to separate logical sections in functions;

  • Python understands the command Ctrl+L as a new blank line, although this input is understood as a page break in other tools.

References

[1] PEP 1 – PEP Purpose and Guidelines.

[2] PEP 8 – Style Guide for Python Code.

comments powered by Disqus
Next

Related