Coding Conventions

Python Coding Conventions

The rules are almost identical to those used by the Docutils project:

Attention

Contributed code will not be refused merely because it does not strictly adhere to these conditions; as long as it’s internally consistent, clean, and correct, it probably will be accepted. But don’t be surprised if the “offending” code gets fiddled over time to conform to these conventions.

The project follows the generic coding conventions as specified in the Style Guide for Python Code and Docstring Conventions PEPs, clarified and extended as follows:

  • Use 'single quotes' for string literals, and """triple double quotes""" for docstrings. Double quotes are OK for something like "don't".

  • No trailing commas.

  • No hanging end-parenthesis.

  • Do not use “*” imports such as from module import *. Instead, list imports explicitly.

  • Use 4 spaces per indentation level. No tabs.

  • Read the Whitespace in Expressions and Statements section of PEP8.

  • Avoid trailing whitespaces.

  • No one-liner compound statements (i.e., no if x: return: use two lines).

  • Maximum line length is 78 characters.

  • Use “StudlyCaps” for class names.

  • Use “lowercase” or “lowercase_with_underscores” for function, method, and variable names. For short names, joined lowercase may be used (e.g. “tagname”). Choose what is most readable.

  • No single-character variable names, except indices in loops that encompass a very small number of lines (for i in range(5): ...).

  • Avoid lambda expressions. Use named functions instead.

  • Avoid functional constructs (filter, map, etc.). Use list comprehensions instead.

Example:

# Copyright (C) 2008  CAMd
# Please see the accompanying LICENSE file for further information.

"""This module is an example of good coding style.

This docstring should begin with a one-line description followed by a
blank line, and then this paragraph describing in more words what kind
of functionality this module implements.

After this docstring we have import statements in this order:

1. From the Python standard library.
2. Other libraries (numpy, ase, ...).
3. GPAW stuff.
"""

from math import pi

import numpy as np
from ase.units import Ha

from gpaw import debug
import gpaw.mpi as mpi


# Use upper case for constants:
CONSTANT = [
    'A',
    'B',
    'C']  # notice: no trailing comma and no hanging end-parenthesis!


class SimpleExample:
    """A simple example class.

    A headline, a blank line and then this longer description of the
    class.

    Here one could put an example of how to use the class::

      ex = SimpleExample('Test', (2, 3), int, verbose=False)
      ex.run(7, verbose=True)

    """

    def __init__(self, name, shape, dtype=float, verbose=True):
        """Create an example object.

        Again, headline, blank line, ... .  If there are many
        parameters, there should be a parameter section (see below).
        If there only a few possible arguments, then the parameter
        section can be left out and the arguments can be described in
        the section following the headline and blank line (see the
        `run` method).  If a method is real simple and
        self-explanatory, the docstring can be the headline only (see
        the `reset` method).

        Parameters:

        name : string
            Name of the example.
        shape:  tuple
            Shape of the ndarray.
        dtype: ndarray datatype
            The datatype of the ndarray.  Here, the description can go
            on to a second line if needed.  Make sure that the
            indentation is like shown here, and remember to end with a
            period.
        verbose: boolean
            Print information about this and that.

        Other sections:

        There can be other sections - see bolow and here:

          https://scipy.org/...

        """

        self.name = name
        if verbose:
            print(name)
        self.a = np.zeros(shape, dtype)
        self.verbose = verbose

    def method_with_long_name(self, b, out=None):
        """Do something very complicated.

        Long story with all details here ...

        Parameters:

        b: ndarray
            Add this array.
        out: ndarray
            Optional output array.

        Returns:

        The sum of ...
        """

        if out is None:
            return self.a + b
        else:
            return np.add(self.a, b, out)

    def run(self, n):
        """Do something.

        Do it n times, where n must be a positive integer.  The final
        result bla-bla is returned.
        """

        for i in range(n):
            self.a += i
            if self.verbose:
                print(self.a)

        return pi * self.a / n + 1

    def reset(self):
        """Simple method - no explanation needed."""
        self.a[:] = 0


def function(a, b):
    """Headline.

    Long story ..."""

    result = a + b
    if debug and mpi.world.rank == 0:
        print(result * Ha)
    return result

General advice

  • Get rid of as many break and continue statements as possible.

  • Write short functions. All functions should fit within a standard screen.

  • Use descriptive variable names.

Writing documentation in the code

ASE follows the NumPy/SciPy convention for docstrings:

C-code

Code C in the C99 style:

for (int i = 0; i < 3; i++) {
    double f = 0.5;
    a[i] = 0.0;
    b[i + 1] = f * i;
}

and try to follow PEP7.

Use M-x c++-mode in emacs.