Skip to content

PythonCodingStyle

Simon Candelaresi edited this page Nov 21, 2019 · 11 revisions

Python Coding Style

Good coding style greatly improves the readability of the code. Similar to the guidelines for the Fortran routines, it is strongly recommended to follow some basic style rules for the python routines. These are some recommendations extracted from PEP 008 and [Google Python Style Guide] (https://google-styleguide.googlecode.com/svn/trunk/pyguide.html).

General Style Guide for Python

Indentation and Spaces

  • Use 4 spaces per indentation level.
  • Use hanging indent for function calls over multiple lines:
# Aligned with opening delimiter.
foo = long_function_name(var_one, var_two,
                             var_three, var_four)
  • Surround top-level function and class definitions with two blank lines.
  • Wildcard imports ( from import * ) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools.
  • More than one space around an assignment (or other) operator to align it with another should be avoided.
    No:
x             = 1
y             = 2
long_variable = 3
  • Always surround these binary operators with a single space on either side: assignment ( = ), augmented assignment ( += , -= etc.), comparisons ( == , < , > , != , <> , <= , >= , in , not in , is , is not ), Booleans ( and , or , not ).
  • If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies).
    Yes:
i = i + 1
submitted += 1
x = x\*2 - 1

No:

i=i+1
submitted +=1
x = x * 2 - 1
  • Don't use spaces around the = sign when used to indicate a keyword argument or a default parameter value.
    Yes:
def complex(real, imag=0.0):
        return magic(r=real, i=imag)

No:

def complex(real, imag = 0.0):
        return magic(r = real, i = imag)

Comments

  • Comments should be complete sentences.
  • Block comments generally apply to some (or all) code that follows them, and are indented to the same level as that code. Each line of a block comment starts with a # and a single space (unless it is indented text inside the comment). Paragraphs inside a block comment are separated by a line containing a single # .

Docstrings

Always use docstrings for classes and functions which can be accessed by the user. Since every individual has different tastes concerning the style we can handle it liberally for the moment. However, always keep the docstring clear and descriptive, explain all parameters and show the default values.

def complex(real=0.0, imag=0.0):
        """Form a complex number.

        Keyword arguments:
        real -- the real part (default 0.0)
        imag -- the imaginary part (default 0.0)
        """

Naming Convention

module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name

Exceptions for >our< code: datadir, varfile, varfiles, ...

pylint

Run pylint over your code. pylint is a tool for finding bugs and style problems in Python source code. It finds problems that are typically caught by a compiler for less dynamic languages like C and C++.

Default Function Arguments

Do not use mutable objects as default values in the function or method definition.
Yes:

def foo(a, b=None):
        if b is None:
            b = []

No: def foo(a, b=[]):

Private Methods

Python does not know any private methods or class member. In order to somewhat hide such methods use two underscores in the function definition: def __magicAttributes(self, param):.

Others

  • Use ''.startswith() and ''.endswith() instead of string slicing to check for prefixes or suffixes. startswith() and endswith() are cleaner and less error prone. For example:
    Yes: if foo.startswith('bar'):
    No: if foo[:3] == 'bar':
  • For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
    Yes:
if not seq:
if seq:

No:

if len(seq)
if not len(seq)
  • Don't compare boolean values to True or False using == .
    Yes: if greeting:
    No: if greeting == True:
  • Check if a variable has a particular type by using isinstance, e.g.: isinstance(my_variable, list).

Pencil Code Specific Style

Classes/Objects

Use classes as much as possible. When you write a function try to embed it into a class as init function which should return the desired result. This has the advantage of adding methods to the returned object which can modify the data. Read-methods always give back objects containing the whole information (container philosophy). Therefore we use classes if possible.

Data Directory

The default data directory is always './data' and not 'data'.

File Headers

Start each file with the file ID, main authors' names and a short description of the routines.

# var.py
#
# Read VAR files. Based on the read_var.pro IDL script.
#
# NB: the f array returned is C-ordered: f[nvar,nz,ny,nx]
#     NOT Fortran as in Pencil (& IDL):  f[nx,ny,nz,nvar]
#
# Author: J. Oishi (joishi@amnh.org).

Import Libraries

  • Import numpy as np instead of N.
  • Import pylab as plt instead of P.

If you need to access libraries in some routines in your module, import them in the routine, rather than the head of the module. That way they are not visible by the user.

Yes:

# my_module.py

class MyClass(object):
    """
    Some documentation.
    """

    def __init__(self):
        import numpy as np

        self.pi = np.pi

No:

# my_module.py
import numpy as np

class MyClass(object):
    """
    Some documentation.
    """

    def __init__(self):
        self.pi = np.pi

Further Reading

https://www.python.org/dev/peps/pep-0008/#tabs-or-spaces

https://google-styleguide.googlecode.com/svn/trunk/pyguide.html