thermondo Developer Handbook
It’s generally good to keep The Zen of Python in mind when writing code.
>>> import this
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!
No need to worry about formatting your code. We use black.
u
for user or i
to iterate over something are
usually not a good idea. Try to be explicit so that the reader can still guess
a variable’s meaning even if the variable is used far away from it’s definition in the code.def _do_something():
id
, str
, or input
are not good variable names
because they are already taken. You can either use trailing underscores to solve the
problem (e.g. id
–> id_
) or you can try to find better explicit names
(e.g. id
–> identifier
).Please use type hints for new code, and feel free to add them to existing code.
*args, **kwargs
, e.g.
def do_whatever(*args, **kwargs): # don't do this
...
Instead, name them explicitly:
def do_whatever(foo: int, bar: int | None = None):
...
Valid exceptions to this rule can be made when you overwrite a function or method from an external source (e.g. overwriting methods from Django classes).
__init__
method of a class. E.g.:
class Something:
def __init__(self, foo=[]) # don't do this, a list is a mutable type
This usually leads to unexpected side effects, like this:
>>> class Something:
... def __init__(self, foo=[]):
... self.foo = foo
...
>>> a = Something()
>>> b = Something()
>>> a.foo
[]
>>> b.foo
[]
>>> a.foo.append('hello')
>>> a.foo
['hello']
>>> b.foo
['hello']
Prefer immutable collection types, e.g.:
>>> class SomethingElse:
... def __init__(self, foo=()):
... self.foo = list(foo)
...
>>> a = SomethingElse()
>>> b = SomethingElse()
>>> a.foo
[]
>>> b.foo
[]
>>> a.foo.append('hello')
>>> a.foo
['hello']
>>> b.foo
[]
lru_cache
.
@lru_cache
def get_best_days():
return {'Saturday', 'Sunday'} # don't do this, a set is a mutable type
This can lead to unexpected side effects, because you are altering the return value of the cache, e.g.:
>>> from functools import lru_cache
>>>
>>> @lru_cache
... def get_best_days():
... return {'Saturday', 'Sunday'}
...
>>> get_best_days()
{'Saturday', 'Sunday'}
>>> best_days = get_best_days()
>>> best_days.add('Wednesday')
>>> get_best_days()
{'Saturday', 'Sunday', 'Wednesday'}
Use an immutable type instead, e.g.:
>>> from functools import lru_cache
>>> @lru_cache
... def get_best_days():
... return frozenset({'Saturday', 'Sunday'})
...
>>> get_best_days()
frozenset({'Saturday', 'Sunday'})
>>> best_days = set(get_best_days()) # cast it to a set if you want to alter the result later
>>> best_days.add('Wednesday')
>>> get_best_days()
frozenset({'Saturday', 'Sunday'})
It’s a balancing act to find the perfect amount of external dependencies. Keep these things in mind:
Remember to verify open source licenses of external packages to make sure commercial use is not restricted or forbidden.
Yes, please! Docstrings are a great way to help manage a long-lived complex code base. We would like to see docstrings for all public classes and functions/methods. But quality goes over quantity. There are valid cases where docstrings are unnecessary or redundant.
def add_two_numbers(a: int, b: int) -> int:
"""Adds 2 numbers.""" # don't do this
return a + b
Classes should be declared in the following order:
__init__
methodExceptions to this rule can be made for example for Django classes. In that case, please refer to our Django style guide.