Keys
Collection keys can be of type str, int, bytes, or a tuple. Keys are stored in an
order-preserving encoding, which is what makes iteration sorted and range scans
possible.
Types
["alice"] = {...} # str
[1699000000] = {...} # int, full 64-bit range
[b"\x01\x02"] = {...} # bytes
[("a", "b")] = {...} # tuple of the aboveInvalid Keys
| Key | Result | Why |
|---|---|---|
1.5 | TypeError | float ordering has NaN and -0.0 hazards |
True | TypeError | bool is an int subclass; it would alias 1 |
None | TypeError | no meaningful position in the ordering |
(1, (2, 3)) | TypeError | tuples are flat, not nested |
2**63 | ValueError | outside the 64-bit range |
Rejection happens at write time, so a bad key never reaches storage.
Ordering
Components sort by type first, then by value: int < str < bytes. Strings compare by their UTF-8 bytes, and tuples compare component-wise.
items =["items"]
for key in [b"q", "z", 5, -1, ("t", 1)]:
[] = {}
list()
# [-1, 5, ('t', 1), 'z', b'q']
Notice that ('t', 1) precedes 'z' because the comparison reaches the first component
before anything else: 't' < 'z'. Tuple keys are not a separate category that
sorts after scalars; they interleave, component by component.
[("a",), ("a", 1), ("a", 2), ("b",)] # already in orderScalar is a 1-tuple
The values "a" and ("a",) are the same key. The encoding treats a scalar as a
one-component tuple, so there is a single code path and no ambiguity:
[("a",)] = {"n": 1}
["a"] # {'n': 1}
list() # ['a']Ranges
The scan for range(start, stop) is half-open. You can use None for unbounded:
c.("a", "m") # 'a' <= key < 'm'
c.(None, "m") # everything below 'm'
c.("a", None) # everything from 'a' up
Both bounds must be the same key type; mixing them raises TypeError.
Prefixes
The method prefix(p) means two different things depending on what you pass:
A string or bytes prefix matches on characters. A tuple prefix matches on whole
components e.g. ("a",) matches ("a", 1) and ("a", "b"), but never ("ab",).
logs.("2026-08") # str: keys of that type beginning with it
blobs.(b"\x01") # bytes: likewise
edges.(("a",)) # tuple: keys whose leading components match