Coding Style Guide¶
The main principles behind pulse2percept development are:
- Robustness: The results of a piece of code must be verified systematically, enhancing stability and reducing redundancies.
- Readability: The code is read much more frequently than it is written, and should be easy to understand by other developers. Documentation is essential.
- Consistency: Following these guidelines will ease reading the code and will make it less error-prone.
Coding style¶
pulse2percept uses the standard Python PEP8 style guide to ensure readibility and consistency of the code base.
Note
There are tools that allow you to automatically check your Python code against PEP8 style conventions.
For example, if you work with Sublime, you can use the PEP8 Autoformat
package. For convenience, make sure the setting autoformat_on_save
is
set to true
.
A few general guidelines:
- Use 4 spaces instead of tab.
- Limit all lines to a maximum of 79 characters.
- Write code for Python 3.5+.
Imports¶
pulse2percept recommends using the following package shorthands to increase consistency and readibility across the library:
import numpy as np
import numpy.testing as npt
import scipy as sp
import pandas as pd
import pulse2percept as p2p
Whitespace and blank lines¶
Don’t use spaces around the =
sign to indicate a keyword argument:
# Good:
def complex(real, image=0.0):
return magic(r=real, i=imag)
# Bad:
def complex(real, image = 0.0):
return magic(r = real, i = imag)
Surround top-level function and class definitions with two blank lines. Use blank lines in functions, sparingly, to indicate logical sections.
Breaking long lines (W503 vs W504)¶
The recommended style is to break a line after binary operators:
# Good:
income = (gross_wages +
taxable_interest -
student_loan_interest)
# Bad:
income = (gross_wages
+ taxable_interest
- student_loan_interest)
Yes, we are aware of the ongoing W503 vs W504 discussion. W504 would improve readibility. However, for now, we want to ensure consistency with the existing code.
Class layout (slots, properties)¶
Classes can have __slots__
that list all class attributes.
This can have several advantages:
- Users cannot add new class attributes on-the-fly. This is desirable for
models (e.g.,
AxonMapModel
), which has a predefined number of attributes. - Slots reduce memory usage. This is desirable for stimuli (e.g.,
TimeSeries
), for which a large number of instances are created.
Subclasses that inherit from classes with __slots__
must themselves
implement slots. The top-level class must inherit from object
, and
attributes cannot be listed more than once:
class Vehicle(object):
__slots__ = ('owner')
def __init__(self, owner):
self.owner = owner
class Car(Vehicle):
__slots__ = ('n_doors')
def __init__(self, owner, n_doors):
self.owner = owner
self.n_doors = n_doors
If you did it right, then neither Vehicle
nor Car
should have a
__dict__
attribute:
car = Car('myself', 4)
assert hasattr(car, '__slots__')
assert not hasattr(car, '__dict__')
This guide was inspired by the `DIPY style guide <https://dipy.org/documentation/1.1.1./devel/coding_style_guideline>`_.