co_linetable says which source line each instruction came from. Python 3.10
introduced it for PEP 626, which guarantees the line numbers a tracer sees: every
executed line is reported, and only those lines. It is a list of pairs of bytes.
Format
Each pair is a range of code and a change of line. They are read in order, with the
byte offset starting at 0 and the line starting at
co_firstlineno.
| Byte | Meaning |
|---|---|
| First | Unsigned: how many bytes of co_code this range covers, 0 to 254 |
| Second | Signed: the change of line for this range, −127 to 127, or −128 to say the range has no line number |
The line delta is added before the range is used, so a range’s delta gives that range’s line. A range of 0 bytes covers no code. A step too big for one pair is split over several: a long range continues in further pairs with a line change of 0, and a large line step uses pairs that cover 0 bytes.
A −128 means the range has no line. The running line is left alone.
Python’s code.co_lines() gives the decoded form: a list of
(start, end, line) entries.
Worked example
This function was compiled under Python 3.10 from t.py, with
def f(a): at line 1:
def f(a):
if a:
return a + 1
return 0
00000000 04 01 08 01 04 01
co_linetable: six bytes, three pairsIts 16 bytes of code are 7C 00 72 06 7C 00 64 01 17 00 53 00 64 02 53 00.
| Pair | Range | Line | Instructions |
|---|---|---|---|
04 01 | Offsets 0 to 4 | +1 → 2 | LOAD_FAST, POP_JUMP_IF_FALSE |
08 01 | Offsets 4 to 12 | +1 → 3 | LOAD_FAST, LOAD_CONST, BINARY_ADD, RETURN_VALUE |
04 01 | Offsets 12 to 16 | +1 → 4 | LOAD_CONST, RETURN_VALUE |
Python 3.10’s co_lines() gives (0, 4, 2),
(4, 12, 3) and (12, 16, 4) for this code. The line before the
first range is co_firstlineno, 1, so the first delta of +1 is line 2.
The jump in that first range, 72 06 at offset 2, has argument 6, and from
magic 3435 the argument counts instructions: its target is byte 2 × 6 = 12, the start
of the third range.