5.5. String methods and formatting¶
Strings come with a built-in toolbox of methods for inspection and reshaping. Because strings are immutable, every method returns a new string – the original is unchanged.
5.5.1. Inspecting strings¶
str.startswith()/str.endswith()– prefix or suffix test; returnsbool.str.find()– position of the first occurrence of a substring, or-1if absent.str.index()does the same thing but raisesValueErroron absence.str.count()– number of non-overlapping occurrences.inkeyword –"MV" in namereturnsTrueif the substring is anywhere in the string.
>>> name = "OpenMV Cam"
>>> name.startswith("Open")
True
>>> name.find("MV")
4
>>> name.count("m")
1
>>> "Cam" in name
True
5.5.2. Cleaning and case¶
str.strip()– remove leading and trailing whitespace. Pass a string of characters to strip a custom set (s.strip("/")).str.lower()/str.upper()– case conversion.str.replace()– substring substitution.
>>> " hello ".strip()
'hello'
>>> "abc-123".replace("-", "_")
'abc_123'
>>> "OpenMV".lower()
'openmv'
5.5.3. Splitting and joining¶
str.split()– break a string into a list at every occurrence of a separator (default: any whitespace run).str.join()– the inverse: glue a sequence of strings together with the receiver as the separator. This is the efficient way to build a long string from pieces.
>>> "1,2,3".split(",")
['1', '2', '3']
>>> "hello world".split()
['hello', 'world']
>>> ", ".join(["a", "b", "c"])
'a, b, c'
5.5.4. f-strings¶
The simplest way to interpolate values into a string is the
f-string – a string literal prefixed with f. Any expression
inside {} is evaluated and inserted:
>>> name = "OpenMV"
>>> count = 42
>>> f"{name} saw {count} blobs"
'OpenMV saw 42 blobs'
A colon inside the braces introduces a format spec that controls how the value is rendered:
{x:.2f}– float with 2 digits after the decimal point.{x:>10}– right-align in a 10-character field.{x:<10}– left-align.{x:0>4}– pad with leading zeros to width 4.{x:#x}– hexadecimal with a0xprefix.{x:b}– binary representation.
>>> f"pi is roughly {3.14159:.3f}"
'pi is roughly 3.142'
>>> f"reg = {0xAB:#x}"
'reg = 0xab'
>>> for i in range(3):
... print(f"line {i:0>3}")
line 000
line 001
line 002
A single = after the expression name prints both the name and
the value – handy for quick debug prints:
>>> v = 3.14
>>> print(f"{v=}")
v=3.14
5.5.4.1. Integer base conversions¶
Three built-ins do the same job as the :b / :o / :x
format specs but return the converted string directly:
bin()– base 2, with a"0b"prefix.oct()– base 8, with a"0o"prefix.hex()– base 16, with a"0x"prefix.
>>> hex(255)
'0xff'
>>> bin(10)
'0b1010'
>>> oct(8)
'0o10'
The inverse direction – turning a base-N string back into an
integer – uses the int constructor with an explicit
base:
>>> int("ff", 16)
255
>>> int("0b1010", 2) # the "0b" prefix is allowed
10
Reach for these when you want the raw string for an int (for a log line, a config file, a register dump). Reach for the format spec when you want padding, width, or to mix the value with other text in the same f-string.
5.5.5. Older formatting styles¶
f-strings are the recommended style, but two older approaches still work and turn up in existing code:
str.format() – braces with positional or keyword arguments
passed to the .format() method on a template string:
>>> "Hello, {}".format(name)
'Hello, OpenMV'
>>> "{0} + {0} = {1}".format(2, 4)
'2 + 2 = 4'
>>> "{name}: {value}".format(name="frames", value=42)
'frames: 42'
Format specs ({:.2f}, {:>10}, …) work the same as in
f-strings; the only difference is where the value is supplied.
% formatting (printf-style) – a single % operator
substitutes values into format codes, one value per code. Pass
multiple values as a tuple:
>>> "Hello, %s" % name
'Hello, OpenMV'
>>> "%d + %d = %d" % (2, 2, 4)
'2 + 2 = 4'
>>> "%.2f" % 3.14159
'3.14'
The most common type codes are %s (string), %d (integer),
%f (float), and %x (hex).
Each % code can carry modifiers between the % and the
type letter. The full shape is %[flags][width][.precision]type:
width – minimum number of characters the field must take. Shorter values are padded with spaces; longer values overflow.
%10dreserves 10 characters and right-aligns the number.precision – meaning depends on the type. For floats, the number of digits after the decimal point.
%.2fgives two decimal places. For strings, the maximum number of characters to take (%.5struncates to five).flag ``-`` – left-align inside the field.
%-10dputs the digits on the left side with trailing spaces.flag ``0`` – pad with leading zeros instead of spaces (for numeric types).
%05dzero-pads to five digits.flag ``+`` – always show the sign on numbers, including a
+for positives.flag ``#`` – alternate form. For
%xthis prefixes the output with0x; for%oit prefixes0o.
Flags, width, and precision can be combined:
>>> "%10d" % 42
' 42' # width 10, space-padded, right-aligned
>>> "%-10d|" % 42
'42 |' # width 10, left-aligned
>>> "%05d" % 42
'00042' # width 5, zero-padded
>>> "%8.2f" % 3.14159
' 3.14' # width 8, 2 decimal places
>>> "%08.2f" % 3.14159
'00003.14' # width 8, zero-padded
>>> "%+d" % 42
'+42' # explicit sign
>>> "%#06x" % 0xAB
'0x00ab' # 0x prefix, zero-pad to 6 chars total
Both older styles are slower to read and more error-prone than f-strings – reach for f-strings in new code, and recognise the older forms when reading existing code.