This document describes Python practices or styles that should generally be used when adding or modifying Python code in InterUSS repositories. When guidelines below suggest different actions, the guideline nearest the top of this document should generally take precedence.
General style guidelines may be found in a separate document.
Black automatically formats Python code and can be invoked with make format
.
Its style choices take precedence over all other recommendations here to
maintain the ability to always be confident of not introducing invalid
formatting using make format
.
The following should almost always have type annotations according to PEP 484:
- Arguments in function or method declarations
- Return values of functions or methods
- Exception: when it is obvious the function or method has no return value,
the correct return type of
None
may be omitted (though annotating non-returning functions or methods with-> None
is still encouraged)
- Exception: when it is obvious the function or method has no return value,
the correct return type of
- Class member variables
- Complex or confusing local variables within a function (PEP 526)
The type Any
should usually be avoided if a more specific type is known.
When the purpose or behavior of a function or method, its input parameters, or its result is not reasonably obvious from its name and typing, it should at least be:
- given a docstring explaining at least the components (input parameters, return value, behavior of function) that are not obvious, or
- annotated as private or internal with a single leading underscore in its name.
Docstrings should be via PEP 257. Google format is encouraged.
Documentation should not consist solely of a reiteration of a component's name. If that is sufficient documentation, then comment-based documentation is not necessary.
Docstrings should not have any empty values. If documentation is not needed for a particular parameter, return type, etc, that part of the docstring should be omitted:
Yes (assuming the purpose and usage of bar
is obvious):
def foo(bar: int, baz: str) -> None:
"""Foos the bar and baz.
Args:
baz: Name of a thing.
"""
No:
def foo(bar: int, baz: str) -> None:
"""Foos the bar and baz.
Args:
bar:
baz: Name of a thing.
"""
Avoid using dict
s with fixed key names for structured data. For data
structures that will not need to be serialized or deserialized, annotate a class
as a dataclass
. For
data structures that may need to be serialized or deserialized, create a class
that inherits from ImplicitDict
.
Avoid named tuples unless performance is important.
No:
my_plain_dict = {"field1": "foo", "field2": "bar"}
x = my_plain_dict["field1"]
y = my_plain_dict["field2"]
Yes:
from dataclasses import dataclass
@dataclass
class MyObject(object):
field1: str
field2: str
my_dataclass = MyObject(field1="foo", field2="bar")
x = my_dataclass.field1
y = my_dataclass.field2
Yes:
from implicitdict import ImplicitDict
class MyObject(ImplicitDict):
field1: str
field2: str
my_implicitdict = MyObject(field1="foo", field2="bar")
x = my_implicitdict.field1
y = my_implicitdict.field2
By default, the Python styles recommended in PEP 8 should be followed.