Python 3 min read

Values and types

Every Python value has a type, but you never declare it. An int grows as large as it needs, so it never overflows the way a uint8_t does. And text (str) is not the same as the raw bytes a UART sends.

A Python value is one of several families: numbers (int, float, bool), text (str), raw bytes (bytes, bytearray) and collections (list, tuple, dict). Bytes are what hardware sends; str is text for people.
The everyday types, grouped by what they hold.

Numbers without overflow

Python has no uint8_t or int32_t. An int has arbitrary precision: 2 ** 64 just works. That is convenient, but firmware arithmetic wraps. When you model what a register or counter on the chip would hold, mask the result yourself. A float is a 64-bit double, like C's double, with the same rounding surprises.

types.pyPython
reading = 300            # an int: as big as it needs to beprint(reading, reading & 0xFF)  # & 0xFF keeps what a uint8_t would holdprint(2 ** 64)print(0.1 + 0.2)print(type(3.3), type("ok"), type(b"ok"))
Output
300 44
18446744073709551616
0.30000000000000004
<class 'float'> <class 'str'> <class 'bytes'>

Collections hold many values. A list such as [3.31, 3.30] grows as you append readings. A tuple is a fixed group, handy for a (time, value) pair. A dict maps keys to values, like register names to offsets: {"CTRL": 0x00, "STATUS": 0x04}. You will use all three when you parse logs later.

Text is not bytes

A str holds text: Unicode characters. A bytes object holds raw 8-bit values, which is what a serial port, a file or a socket delivers. Convert between them on purpose: encode() turns text into bytes, and decode() turns bytes into text. Indexing bytes gives you an int, not a character.

bytes_vs_str.pyPython
command = "AT\r\n"raw = command.encode("ascii")print(raw, len(raw), raw[0])print(raw.decode("ascii").strip())
Output
b'AT\r\n' 4 65
AT