Python 3 min read

Functions and modules

A function puts a name on a piece of work: def checksum(data) once, then call it anywhere. A module is just a .py file of such functions, so your bench scripts can share helpers instead of copying them.

frames.py holds checksum() and is_valid(). bench.py imports it to check frames from the board, and test_frames.py imports the same module to test the helpers.
Write the helpers once, import them everywhere.

def and return

def names a function and lists its parameters. return hands a value back to the caller; a function without it returns None. The optional hints after the colons, such as data: bytes, document what goes in and comes out. Python doesn't enforce them, but editors and checkers use them.

frames.pyPython
def checksum(data: bytes) -> int:    """8-bit sum of every byte, as many simple frames use."""    return sum(data) & 0xFFdef is_valid(frame: bytes) -> bool:    return checksum(frame[:-1]) == frame[-1]if __name__ == "__main__":    good = bytes([0xAA, 0x29, 0x09, 0x01, 0xDD])    print(checksum(good[:-1]), is_valid(good))    print(is_valid(good[:-1] + b"\x00"))
Output
221 True
False

A module is a file

Any .py file is a module. Put frames.py next to your script, and from frames import is_valid gives you its function. The standard library is a collection of modules like this: struct, csv, time and pathlib all arrive with a single import.

bench.pyPython
# bench.py: reuse the helpers instead of copying themfrom frames import is_validdef handle(frame: bytes) -> None:    if not is_valid(frame):        print("bad checksum:", frame.hex(" "))

Python runs a module once, the first time it is imported, and reuses it after that. Keep each module small and focused: one for frame helpers, another for talking to the serial port. Then a test can import the frame helpers without a board connected.