# 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 ```