Our Style¶
Philosophy¶
Good code is written once and read many times, so design for readability
. Even if you don’t intend anybody else to read your code, there’s still a very good chance that somebody will have to stare at your code and figure out what it does: That person is probably going to be you, twelve months from now.
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
Some Syntax Considerations¶
Import Statements¶
Use import statements for packages and modules only, not for individual classes or functions.
Note: that there is an explicit exemption for imports from the typing module.
Correct
import x # For importing packages and modules.
from x import y # Where x is the package prefix and y is the module name with no prefix.
from x import y as z # If two modules named y are to be imported or if y is inconveniently long.
import y as z # Only when z is a standard abbreviation, e.g. import numpy as np
Imports should usually be on separate lines:
However, it is okay to do this:
Imports are always put at the top of file, just after module comments and docstrings, but before constants. Imports should be grouped in the following order:
- Standard library imports.
- Related third party imports.
- Local application/library specific imports.
A blank line should be placed between groups.
Naming Convention¶
When naming anything, the names that you give should be meaningful and descriptive. Avoid using throwaway names such as "temp". They should also follow the naming convention below:
package_name
module_name
ClassName
method_name
ExceptionName
function_name
CONSTANT_NAME
var_name
function_parameter_name
local_var_name
Constants¶
Project-wide constants should be placed in a common repository. e.g.
Global Variables¶
Avoid package wide global variables, but rather use module-level constants, which are encouraged.
Exceptions¶
Exceptions are allowed but must be used carefully since they break the normal flow control of the code.
Avoid using catch all except
or catch Exception
.
def connect(self, port: int):
"""Connect to a port
Parameters
----------
port : int
Port number
Raises
------
ConnectionError
Returns
-------
connection: object-type
"""
try:
connection = self._connect_routine(self, port)
except ConnectionError as error:
log.error(error)
return connection
Type Annotations¶
Get to know PEP 484. You are not required to annotate all the functions in a module, but: - Use judgment to get to a good balance between safety and clarity on the one hand, and flexibility on the other. - Annotate code that is prone to type-related errors (previous bugs or complexity). - Annotate code that is hard to understand. - Annotate code as it becomes stable from a types perspective. In many cases, you can annotate all the functions in mature code without losing too much flexibility.
def another(thing: list) -> list:
return thing
def something(self, first_var: int) -> int:
pass
Indentation¶
Indentations should use four spaces per indentation level.
Correct
# Aligned with opening delimiter:
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Add 4 spaces (extra indentation level) to distinguish args
def long_function_name(
var_one, var_two, var_three,
var_four):
print(var_one)
# Hanging indents should add a level
foo = long_function_name(
var_one, var_two,
var_three, var_four)
Wrong
The closing brace/bracket/parenthesis on multi-line constructs may be lined up with the first non-whitespace character:
or it may be lined up under the first character the starts the multi-line construct:
Binary Operators and Line Breaks¶
Previously, the recommended style was to break after the binary operator, but this makes the eye do extra work to tell which are added and which are subtracted:
Wrong
However, following tradition from mathematics results in more readable code: