We mainly use PEP8 for all python code.
The main additions outside of PEP8 are:
A summary of the most commonly used conventions are:
MyClassUPPERCASE_WITH_UNDERSCORESsnake_caseFor a bonus illusration of the case-naming conventions, see the bottom of the page.
It it recommended to have an automatic linter installed such as
flake8 that can be integrated directly into the IDE and the
ci/cd pipelines.
For example, for Sublime Text, using the package SublimeLinter with the following settings:
// SublimeLinter Settings - User
{
"linters": {
"flake8": {
"disable": false,
"args": [
"--ignore=E251,E126,E226",
"--max-line-length=79",
],
},
},
}The above will highligt most code-style issues. Here the ignored items are
* and
/ can be broken for readability)With regards to E226, PEP8 also states that
If operators with different priorities are used, consider adding whitespace around the operators with the lowest priority(ies). Use your own judgment; however, never use more than one space, and always have the same amount of whitespace on both sides of a binary operator.
Most IDE’s also have the option of column rulers and this should also
be used. Again for the example of Sublime Text this is set by adding
"rulers": [79,110], to the general configuration.
Style guides are important for scientific software for readability of code. If the code is readable, contributions are easier, maintinance is easier and validation of the implemented physics or mathemetics is easier. As an example, consider parsing these two pieces of code that perform the exact same operations:
import numpy as n
import scipy.constants as c
def gmf(x, z_tx, z_rx, o):
r0,v0,a0=x[0],x[1],x[2]
rng=r0+v0*o.tau+0.5*a0*o.tau**2.0
phase=n.exp(-1j*n.mod(2.0*n.pi*rng/o.lam,2.0*n.pi))
rng_samples=n.array(n.round(o.sample_rate*rng/c.c),dtype=n.int)
idx=n.arange(o.n_ipp*o.ipp)
mf=z_rx[rng_samples+idx]*phase*z_tx
s=n.abs(n.sum(mf))
return(-s)versus
import numpy as np
import scipy.constants as constants
def generalized_match_function(
parameters,
transmitted_waveform,
recived_waveform,
radar
):
'''Calculates the generalized match function by shifting the transmitted
waveform according to a given phase offset model, dependent on the input
parameters in `x`, and convolving with the received waveform[1]_.
Parameters
----------
parameters : numpy.ndarray or list
Phase offset model parameters, must contain three elements.
transmitted_sig : numpy.ndarray
The transmitted waveform.
recived_sig : numpy.ndarray
The received waveform.
radar : this_package.Radar
Radar instance containing the radar specific information.
Returns
-------
float
Negative of the generalized match function absolute value.
.. [1] Markkanen, J., Lehtinen, M., Landgraf, M., 2005.
Real-time space debris monitoring with EISCAT,
https://doi.org/10.1016/j.asr.2005.03.038
'''
range0 = parameters[0]
vel0 = parameters[1]
accel0 = parameters[2]
dt = radar.sample_time
target_range = range0 + vel0*dt + 0.5*accel0*dt**2.0
phase_angle = 2.0*np.pi*target_range/radar.wavelength
phase_angle = np.mod(phase_angle, 2.0*np.pi)
phase = np.exp(-1j*phase_angle)
range_in_samples = np.array(
np.round(radar.sample_rate*target_range/constants.c),
dtype=np.int,
)
# IPP stands for Inter Pulse Period
total_ipps = radar.ipp_number*radar.ipp_length
waveform_inds = range_in_samples + np.arange(total_ipps)
match_function = recived_waveform[waveform_inds]*phase*transmitted_waveform
match_value = -np.abs(np.sum(match_function))
return match_valueThe first code listing is shorter and more compact, but much harder to decypher for a fresh pair of eyes.
Below is an example editor config that supports the PEP8 standard
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
[*.py]
max_line_length = 79
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
Some editors require plugins to support the editorconfig file as is.