# High level development guidelines
## Python Good Practice
### Typing
Always type the code (explicitly specify the type of arguments and return value).
It's usefull because the code become more explicit, better documention can be generated, and this IDE to do good auto-completion.
See [https://docs.python.org/3/library/typing.html](https://docs.python.org/3/library/typing.html)
### Slots
Use the `__slots__` member variables every time it's possible on classes.
This special variable is usefull to greatly reduce memory usage (classes declared with a `__slots__` variable take less space than a tuple).
See [https://wiki.python.org/moin/UsingSlots](https://wiki.python.org/moin/UsingSlots)
### Comments
Please comment the code when needed.
Don't write obvious comment like this:
```py
x = x + 1 # Increment x
```
But this is fine:
```py
x = x + 1 # Compensate for border
```
### String formating
For string formation prefer first using `f-strings` then `%` operator and finally the `.format(...)` function.
The `f-strings` is the fastest and most modern way to do string formating.
Then the `%` is the second fastest and `.format(...)` the slowest way.
For readability concerns, `f-strings` is also the best.
The `%` operator use a more leightweight syntax than the `.format(...)` function but the `.format(...)` function use a more regular syntax.
Any way please avoid string concatenation because it can be really hard to read.
For more details on how to do string formating, see:
[https://realpython.com/python-string-formatting/](https://realpython.com/python-string-formatting/)
---
## Python Coding Style
### Function name
All global and member function name must be in snake_case.
```py
def set_speed(speed: float) -> None:
pass
```
### Classes
All classes name must be in PascalCase.
```py
class ServoDevice(Device):
pass
```
### Function and classes scope
In Python every class method, or attribute that starts with (but doesn't end with) two underscores, it's private.
Their is no standard for protected method but please use a simple underscore to start at the begining and nothing at the end to specifiy that a method is protected.
All other name are for public methods.
```py
# Public method
def shutdown() -> None:
pass
# Private method for the whole file
def __clean_exit(code: int = 0) -> None:
pass
# There is no concept of protected methods at file scope
# Public class
class PWMServoDriver(ServoDevice):
# Public method (because it's end with __)
def __init__(self):
super().__init__()
# Public member method
def set_angle(angle: float) -> None:
self._set_duty_cycle_percent(angle / 360.0)
# Protected member method
def _set_duty_cycle_percent(value: float):
self.__set_pwm(int(value * 1024))
# Private member method
def __set_pwm(value: int ):
pass
```
### Line break for long formula
It's better to put the line break before the operator for readability.
```py
income = (gross_wages
+ taxable_interest
+ (dividends - qualified_dividends)
- ira_deduction
- student_loan_interest)
```
### Trailing spaces
Avoid useless trailling spaces at end of lines (there is plugins on VS Code to check that).
### Indentation
Please indent the code with 4 space and no tabs. It's allow every reader to display rougly the same identation width because the number of space that make a tab is implementation dependants.
### Files name
All Python files name must be in snake_case.
### Imports
Imports should usually be on separate lines.
```py
# Correct:
import os
import sys
# Wrong:
import sys, os
```
### String quotes
For triple-quoted strings, always use double quote characters to be consistent with the docstring convention.
Otherwise, prefer using the double quoted string. But sometime it's improve readability to use simple quoted string when you don't want to escape double quotes that are inside the string.
```py
# Correct:
"""
A multiline,
comment or string.
"""
name = "Félicia la chatte"
# The following string is fine because their is double quote,
# so it's better to not escape them for readability
print(f'Name: "{name}"')
# Wrong:
'''
A bad multiline,
comment or string.
'''
# Here their is no need to use simple quote so prefer double quotes.
name = 'Félicia la chatte'
```
### Whitespaces
#### Avoid extraneous whitespace in the following situations:
Immediately inside parentheses, brackets or braces:
```py
# Correct:
spam(ham[1], {eggs: 2})
# Wrong:
spam( ham[ 1 ], { eggs: 2 } )
```
Between a trailing comma and a following close parenthesis:
```py
# Correct:
foo = (0,)
# Wrong:
bar = (0, )
```
Immediately before a comma, semicolon, or colon:
```py
# Correct:
if x == 4: print(x, y); x, y = y, x
# Wrong:
if x == 4 : print(x , y) ; x , y = y , x
```
However, in a slice the colon acts like a binary operator, and should have equal amounts on either side (treating it as the operator with the lowest priority). In an extended slice, both colons must have the same amount of spacing applied. Exception: when a slice parameter is omitted, the space is omitted:
```py
# Correct:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
# Wrong:
ham[lower + offset:upper + offset]
ham[1: 9], ham[1 :9], ham[1:9 :3]
ham[lower : : step]
ham[ : upper]
```
Immediately before the open parenthesis that starts the argument list of a function call:
```py
# Correct:
spam(1)
# Wrong:
spam (1)
```
Immediately before the open parenthesis that starts an indexing or slicing:
```py
# Correct:
dct['key'] = lst[index]
# Wrong:
dct ['key'] = lst [index]
```
#### But do not forget whitespace in the following situations:
Just before and after the equal sign for named arguments and default values:
```py
# Correct:
def munge(input: AnyStr, sep: AnyStr = None, limit = 1000):
munge(input, limit = limit - 1)
```
Before and after the arrow to specify return value type:
```py
# Correct:
def get_env(key: str) -> str | None:
pass
# Wrong:
def get_env(key: str)-> str|None:
pass
```