Python PEP 8 – How to style correctly your Python code

PEP 8 Style Guide of Python

Python is evolving using PEP (Python Enhancement Proposal), but there are some particular ones that are quite special because they are used as a guide for some parts of the language.

The Python Enhancement Proposal number 8 (PEP 8) is a guide that defines how the Python code should be written in order to consider python pythonic and is a key guide that every pythonista must know an follow.

Following the rules present on this PEP, the python code should follow the same standard and rules and it can be used to identify distinguish a correctness of a code style in any situation.

Python style guide

In this section, the proposal defines the key points on how the python code should be written at a design level to convert usual code into pythonic one. Topics like lines length, indentation or import order are covered in this section.

Indentation rules at PEP 8

Python code defines the internal logic of each section using indentation. This indentation can be done using an certain amount of spaces or tabs but the recommendation on the PEP-8 rules that it should be used 4 spaces always.

This recommendation make sense in the way that spaces always uses a similar amount of space to be shown, while tabs, depending on the editor that would be used, it could use more or less space, making the code to looks funny or even unreadable in some situations.

def es_par(num):
    if num % 2 == 0:
        return True
    return False

The indentation is also present when there are arguments definitions. All the arguments should be defined on 2 levels of the next indentation logic block or aligned on the open parenthesis of the function parameters definition.

This rule helps to easily detect the code from the arguments definition as can be seen on the next example.

def function_with_arguments(arg_1,
    arg_2,
    arg_3):
    print(arg_1)
def function_with_arguments(arg_1,
                            arg_2,
                            arg_3):
    print(arg_1)

# or
def function_with_arguments(
        arg_1, arg_2,
        arg_3):
    print(arg_1)

Since Python 3, it is forbidden the mix between spaces and tabulations for indentation, but if you are still using Python 2, you can run some code using -t or -tt to identify if there are some mixing indentation characters used.

Lines length rules

The PEP8 allows some flexibility on the lines length due to the fact that more often we are using width screens for programming and some programming teams has different preferences when writing code:

  • 79 maximum characters must be used by default and when writing code for the Python build-in.
  • 72 maximum characters for comments lines and documentation.
  • 99 maximum characters for the exception of teams that accord to use larger lines length but keeping the limit of 72 characters for comments and documentation.

The result of the application of this rule is to enable the use of multiple windows with code opened at the same time with no need to use the horizontal scrolling, and improve the readability.

On large lines, it can be used the character \ to split the line and continue writing on the next line:

def my_function(arg_1,
                second_param='tree',
                third_param=None):
    return True

# another example
if peso > 93 and days_to_summer < 100 \
        and holidays_destination = 'Beach':
    start_working_out()

Placing operators correctly

When there are operators at a new lines, the new lines must start with the operator, because it improves the readability.

total_legs = (num_cat_legs +
              num_duck_legs +
              num_dog_legs)
total_legs = (num_cat_legs 
              + num_duck_legs 
              + num_dog_legs)

Blank lines

The blank lines can help a lot to improve the readability of the code, and that’s why there is some room on the PEP 8 for them showing how to use them properly.

  • 2 blank lines: between functions and classes definitions.
  • 1 blank line: on the method definition of a class.
  • 1 extra blank line: between different blocks of logic (even on the same function) to help visual logic distinction.
  • 1 last blank line: all the Python modules should end on a blank line at the end of the file.
  • control-L (^L): it is rarely used to separate pages of logic (it is supported by some editors).
INIT_CONSTANT = 'start'

def foo(a):
    return a + 5


class Dog:
    weight = 2.1

    def bark(self):
        print('uau!')

    def eat(self):
        self.weight += 0.2

Code import rules

There are some import rules to define how to do it properly:

  • The import statements must be on a separate lines.
  • The lines order must be: build-in, third party libraries and then custom libraries (libraries of the project).
  • The imports should use absolute paths when possible.
  • The imports using relative paths should be explicit, simple and shorts.
  • The use of wildcards (*) should be avoided because is implicit and can create easily side effects.
# wrong
import sys, so

# correct
import sys
import so
from json import dump, load

# absolute paths
import my_pkg.functions
from my_pkg import functions
from my_pkg.functions import a_single_function

# relative paths
from . import my_pkg
from .my_pkg import functions

# to avoid
from my_pkg import *

Variables on a module

There are certain special names that can be used to define module aspects:

  • __all__: defines the objects that could be imported from the module (it is handy to limit the import when using *).
  • __author__: allow to define the author of the module.
  • __version__: specify the version of the module.

All of those special name variables should be declared at the beginning of the module, right below the import statements.

String literals definitions

Python strings literals can be defined using different characters and some of them have particular meanings.

  • Characters surrounded by simple or double quotes: they define strings of a single line.
  • Characters surrounded by triple double quotes: they are used to define documentation blocks and they must appear at the first line after the definition of the function/method header.
def my_function_foo():
    """Documentation section"""
    pass

a = "Ander's car"  # in order to use ', the string must use "
date = 'the book named "Python a fondo" is awesome'  # viceversa

Usage of spaces

In the PEP 8 there are certain usages of the spaces that are highlighted. The use of spaces can improve readability or add overhead so there are some rules to add or avoid the usage of them:

  • Add spaces: between elements comma separated, at both sides of operational elements, at values assignations or separating operations blocks.
  • Avoid spaces when using slicing, right before parenthesis, on the functions names, acceding to variables using [], at logically joined operations or at empty parenthesis.
my_function_foo(param1, [1, 2])

a += 1
i = i + 1
b = a*2 - 1
c = (a+i) * (a-i)

if a == b:
   print(a + ' is equal than ' + b)

lst[1:2], lst[4:], lst[5:34:2]
lst[start + mid : mid + end]
lst[start::end]

cat = 1
dog = 2
brown_elephant = 4
my_function_foo ( param1, [  1,   2] )

a +=1
i=i+1
b = a * 2 - 1
c = (a + i) * (a - i)

if a==b:
   print (a+' is equal than '          +   b)

lst[ 1:2 ], lst[ 4:], lst[5 : 34 : 2]
lst[start + mid:mid + end]
lst[start : : end]

cat            = 1
dog            = 2
brown_elephant = 4

Trailing commas

In python, when there are 2 variables separated by comma it is creating a tuple using the literal form, so it would be better to explicitly add the parenthesis when trying to create a tuple literal.

variable = ('123',)
my_function(param1,
            param2,
            )
variable = '123',  # implicit way to create a tuple
my_function(param1, param2,)  # The trailing comma is redundant here

When using several values it is not needed to add a comma at the end. It is recommended to use a new line because also will help to keep the changes in git clearer.

Comments

There are many rules at PEP 8 trying to rule the way comments should be written in Python:

  • Comments can be contradictory and require updates along with the code, so it is better to get avoided making explicit and clean code.
  • Comments must be complete frases.
  • All comments must start with uppercase, except when the first word is a lower cased identifier.
  • Comments blocks are entire paragraphs ending on a dot.
  • All comments should be written in English, unless you are 120% sure that the reader of the code will understand them on other language.
  • Comments are applied to the code right after them and at the same indentation level.
  • On a single line comments, they start with a # and starting with 2 spaces.
  • Docstrings should be added to classes, functions and methods following the PEP 257.
# Single line comment
def foo(arg_1, arg_2):
    """Docstring to describe the function foo
    arg_1 -- arg_1 description
    arg_2 -- arg_2 description
    """
    pass

Names conventions

There are some rules to apply on each object type.

  • Characters to avoid: o, O, l or L (letter O or letter L) because they can be confused with 0 or 1 depending on the font used.
  • ASCII characters: they must be the only one used on the build-in.
  • Modules and packages names: they should be written in lowercase and avoiding the several words, but always must be joined by underscore.
  • Classes name: they must be used in CapitalFormat where the first letter of each word must be uppercase and the rest in lowercase.
  • Types names: it should use CapitalFormat.
  • Exceptions: using CapitalFormat but with the suffix Error.
  • Variable and function names: always using lowercase and underscore separated words.
  • Class methods: the first parameter of the class methods should be self and the first parameter of a class method should be cls.
  • Constante: always in uppercase separated by underscores if needed.
from vehicles import Car

MAX_MOVE = 500

class KilometerLimitError(Exception):
    pass

class Saet(Car):
    position = 0

    def move(self, num_km):
        new_position += num_km

        if new_position > MAX_MOVE:
            self.position = MAX_MOVE
            raise KilometerLimitError()
        else:
            self.position = new_position

Variable annotations

At PEP 526 there were introduced the annotations into the language to help hint the type ofs of variables and arguments:

  • Declaration: <variable_name>: <type>
  • Declaration + initialization: <variable_name>: <type> = <default>
num_legs: int

class Car:
    num_wheels: int = 4

PEP8 checker – How to detect PEP 8 errors?

There are libraries to detect errors and violation of rules. Usually those libraries are included at IDEs and Editors specialized in Python.

However, there is a program that can be run on any Python project pycodestyle (early called pep8). It can be run as follow:

$ pip install pycodestyle
$ pycodestyle --first nombre_fichero.py
...
$ pycodestyle --show-source --show-pep8 nombre_fichero.py
...
$ pycodestyle --statistics -qq nombre_fichero.py
...

Recommended books to learn Python

This is a list of recommended books to learn Python, how to program, data types, algorithms and much more.

Disponible en:

Share

1 Response

Leave a Reply

Your email address will not be published. Required fields are marked *

Ver más

  • Responsable: Oscar Ramirez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento: No se ceden o comunican datos a terceros para prestar este servicio. El Titular ha contratado los servicios de alojamiento web a ionos (1&1) que actúa como encargado de tratamiento.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

Post comment