Skip to content

Style guide for repository code

Reyk edited this page Jan 6, 2022 · 1 revision

Python

This is only a summary of the most important points. Here can find the complete python style guide

Why do we need a style guide?

Code is, in general, read much more often than it is written. The guidelines provided here are intended to improve the readability of code and make it consistent. Readability counts Consistency with this style guide is important. Consistency within a project is more important. Consistency within one module or function is the most important.

A style guide will add a well-thought-through structure to the code. This makes it more readable and, therefore, easier to understand and maintain.

As mentioned, consistency is the key and not the precise implementation of the style guide! When applying the guideline would make the code less readable this guide can be ignored.

Code Lay-out

Indentation

Use 4 spaces per indentation level.

Continuation lines should align wrapped elements either vertically or using a hanging indent. When using the last there should be no arguments on the first line and further indentation should be used to clearly distinguish itself as a continuation line.

When using hanging indentation the closing bracket, brace or parenthesis should be on the next line with default indentation.

# Correct:

# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                         var_three, var_four)

# Add 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
)

# Wrong:

# Arguments on first line forbidden when not using vertical alignment.
foo = long_function_name(var_one, var_two,
    var_three, var_four)

# Further indentation required as indentation is not distinguishable.
def long_function_name(
    var_one, var_two, var_three,
    var_four):
    print(var_one)

# Closing paranthesis on the same line as arguments.
foo = long_function_name(
    var_three, var_four)

When using if statements with multiple expressions the statement plus a single space and an opening parenthesis creates a natural 4 space indentation when aligning continuation lines.

if (this_is_one_thing and
    that_is_another_thing):
    do_something()

To better visually distinguish such conditional lines use either a comment after the statement or extra indentation.

# supporting syntax highlighting.
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()

Maximum line length

Limit all lines to a maximum of 99 characters. Docstrings and comments should be limited to 72 characters.

Limiting the required editor window width makes it possible to have several files open side by side, and works well when using code review tools that present the two versions in adjacent columns.

The preferred way of wrapping long lines is by using Python's implied line continuation inside parentheses, brackets and braces. Long lines can be broken over multiple lines by wrapping expressions in parentheses. These should be used in preference to using a backslash for line continuation.

Backslashes may still be appropriate at times. For example, long, multiple with-statements cannot use implicit continuation, so backslashes are acceptable:

with open('file1') as file_1, \
     open('file2', 'w') as file_2:
    file_2.write(file_1.read())

Another such case is with assert statements.

Line break before a Binary Operator

When breaking after the Binary Operator, operations get scattered across different columns on the screen, and each operator is moved away from its operand and onto the previous line. The eye has to do extra work to tell which items are added and which are subtracted, which hurts readability:

# Wrong:
# operators sit far away from their operands
income = (gross_wages +
          taxable_interest +
          (dividends - qualified_dividends) -
          ira_deduction -
          student_loan_interest)

# Correct:
# easy to match operators with operands
income = (gross_wages
          + taxable_interest
          + (dividends - qualified_dividends)
          - ira_deduction
          - student_loan_interest)

Blank lines

Surround top-level function and class definitions with two blank lines.

Method definitions inside a class are surrounded by a single blank line.

Extra blank lines may be used (sparingly) to separate groups of related functions. Blank lines may be omitted between a bunch of related one-liners.

Use blank lines in functions, sparingly, to indicate logical sections.

Imports

Imports should usually be on separate lines:

# Correct:
import os
import sys

# Wrong:
import sys, os

It's okay to this though:

# Correct:
from subprocess import Popen, PIPE

Imports are always put at the top of the file, just after any module comments and docstrings, and before module globals and constants. Imports should be grouped in the following order:

  1. Standard library imports.
  2. Related third party imports.
  3. Local application/library specific imports.

You should put a blank line between each group of imports. For each group the direct imports are written at first (import ...) followed by the imports of submodules (from ... import ...).

Wildcard imports (from import *) should be avoided, as they make it unclear which names are present in the namespace.

Comments

Long multiline comments should be wrapped in three double quotes and start directly after the opening. The body should have no default extra indentation and should align with the opening quotes.

# Wrong:
# This is an example documentation comment
# This is the body of the comment.

# Correct:
"""This is an example

This is the body of the comment
"""