Every .pyc file of this format starts with the same 16 bytes of header,
all little-endian. The header says which release wrote the file and how to tell whether
it is out of date. The module’s code object follows at offset 16.
0magic: the number, then0D 0A4 bytes4flags4 bytes8source_mtime, or the first half of source_hash4 bytes12source_size, or the second half of source_hash4 bytes
Magic number
The first two bytes are a 16-bit number, and the next two are always
0D 0A, a carriage return and a line feed. A file copied in text mode has
those bytes changed, so the magic number no longer matches and the file is rejected.
CPython changes the number whenever the bytecode changes in a way an older interpreter cannot run. Python 3.n starts at 2900 + 50n, and the number goes up by one for each change within that release. A file loads only on a release with exactly the same number. The file does not say which release it came from in any other way.
The final number of each release is below; the full list follows further down.
| Release | Magic | Bytes |
|---|---|---|
| 3.11 | 3495 | A7 0D 0D 0A |
| 3.12 | 3531 | CB 0D 0D 0A |
| 3.13 | 3571 | F3 0D 0D 0A |
| 3.14 | 3627 | 2B 0E 0D 0A |
| 3.15 | 3666 | 52 0E 0D 0A |
Flags
A 32-bit field that says how the file is checked against its source. Two bits are defined by PEP 552, and CPython rejects a file with any other bit set.
| Bit | Meaning |
|---|---|
| 0 | Set: the next 8 bytes are a hash of the source. Clear: they are the source’s date and size. |
| 1 | Only with bit 0: the hash is checked against the source when the file is loaded. |
| Value | Kind of file |
|---|---|
| 0 | Checked by the source’s date and size. The usual kind. |
| 1 | Hash-based, not checked when loaded. The file is used even if the source has changed. |
| 3 | Hash-based, checked when loaded. The source is hashed and the file is used only if the hash matches. |
The value 2, bit 1 alone, is never written. The explorer turns it down.
py_compile and compileall make hash-based files with their
invalidation mode options.
source_mtime
Unsigned 32-bit, at offset 8, when flags is 0. The source file’s modification time in seconds since 1970, as a Unix timestamp, kept to 32 bits. A file is stale if this differs from the source file’s current time.
source_size
Unsigned 32-bit, at offset 12, when flags is 0. The size of the source file in bytes, modulo 232. A file is stale if this differs from the source’s current size.
source_hash
8 bytes at offset 8, when bit 0 of flags is set. A 64-bit SipHash of the source file’s
bytes, keyed by the magic number. importlib.util.source_hash() computes
it. Python’s importer does not recompute it when flags is 1.
Examples
00000000 2B 0E 0D 0A 00 00 00 00 00 F1 53 65 06 00 00 00
0x6553F100 (1700000000, 14 November 2023), source size 6 bytes00000000 2B 0E 0D 0A 03 00 00 00 1D B2 B6 32 5C A2 82 A7
File names and folders
importlib stores a module’s compiled form in a __pycache__
folder beside the source, named with the interpreter’s tag, as PEP 3147 describes.
The tag gives the release, so several versions of Python can share one source folder.
| Source | Compiled |
|---|---|
spam.py, Python 3.11, no optimisation | __pycache__/spam.cpython-311.pyc |
spam.py, Python 3.14 with -O | __pycache__/spam.cpython-314.opt-1.pyc |
spam.py, Python 3.14 with -OO | __pycache__/spam.cpython-314.opt-2.pyc |
A spam.pyc file with no spam.py beside it is loaded as a
module that has no source. The .pyo extension is not used in this format.
All magic numbers
The list is the one in CPython’s own source,
Include/internal/pycore_magic_number.h. Numbers marked final are those of a
released version. Other numbers come from alphas, betas and release candidates, and
the release shown is the pre-release that introduced them.
| Magic | Release | What changed |
|---|---|---|
| 3450 | 3.11a1 | Use the exception table for unwinding (“zero cost” exception handling) |
| 3451 | 3.11a1 | Add CALL_METHOD_KW |
| 3452 | 3.11a1 | Drop nlocals from marshalled code objects |
| 3453 | 3.11a1 | Add co_fastlocalnames and co_fastlocalkinds |
| 3454 | 3.11a1 | Compute cell offsets relative to locals |
| 3455 | 3.11a1 | Add MAKE_CELL |
| 3456 | 3.11a1 | Interleave cell arguments |
| 3457 | 3.11a1 | Change localsplus to a bytes object |
| 3458 | 3.11a1 | Imported objects no longer use LOAD_METHOD and CALL_METHOD |
| 3459 | 3.11a1 | PEP 657: add end line numbers and column offsets for instructions |
| 3460 | 3.11a1 | Add the co_qualname field |
| 3461 | 3.11a1 | JUMP_ABSOLUTE must jump backwards |
| 3462 | 3.11a2 | Remove COPY_DICT_WITHOUT_KEYS; change MATCH_CLASS and MATCH_KEYS; add COPY |
| 3463 | 3.11a3 | JUMP_IF_NOT_EXC_MATCH no longer pops the active exception |
| 3464 | 3.11a3 | Merge the numeric BINARY_* and INPLACE_* instructions into BINARY_OP |
| 3465 | 3.11a3 | Add COPY_FREE_VARS |
| 3466 | 3.11a4 | PEP 654: except* |
| 3467 | 3.11a4 | Change the CALL_xxx instructions |
| 3468 | 3.11a4 | Add SEND |
| 3469 | 3.11a4 | Remove type and traceback from exc_info |
| 3470 | 3.11a4 | PREP_RERAISE_STAR no longer pushes lasti |
| 3471 | 3.11a4 | Remove POP_EXCEPT_AND_RERAISE |
| 3472 | 3.11a4 | Replace GEN_START with POP_TOP |
| 3473 | 3.11a4 | Add POP_JUMP_IF_NOT_NONE and POP_JUMP_IF_NONE |
| 3474 | 3.11a4 | Add RESUME |
| 3475 | 3.11a5 | Add RETURN_GENERATOR |
| 3476 | 3.11a5 | Add ASYNC_GEN_WRAP |
| 3477 | 3.11a5 | Replace DUP_TOP and DUP_TOP_TWO with COPY; ROT_TWO, ROT_THREE, ROT_FOUR and ROT_N with SWAP |
| 3478 | 3.11a5 | New CALL instructions |
| 3479 | 3.11a5 | Add PUSH_NULL |
| 3480 | 3.11a5 | New CALL instructions, second iteration |
| 3481 | 3.11a5 | Use an inline cache for BINARY_OP |
| 3482 | 3.11a5 | Use inline caching for UNPACK_SEQUENCE and LOAD_GLOBAL |
| 3483 | 3.11a5 | Use inline caching for COMPARE_OP and BINARY_SUBSCR |
| 3484 | 3.11a5 | Use inline caching for LOAD_ATTR, LOAD_METHOD and STORE_ATTR |
| 3485 | 3.11a5 | Add an argument to GET_AWAITABLE |
| 3486 | 3.11a6 | Use inline caching for PRECALL and CALL |
| 3487 | 3.11a6 | Remove the adaptive “oparg counter” mechanism |
| 3488 | 3.11a6 | LOAD_GLOBAL can push an additional NULL |
| 3489 | 3.11a6 | Add JUMP_BACKWARD, remove JUMP_ABSOLUTE |
| 3490 | 3.11a6 | Remove JUMP_IF_NOT_EXC_MATCH, add CHECK_EXC_MATCH |
| 3491 | 3.11a6 | Remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH and JUMP_BACKWARD_NO_INTERRUPT, make JUMP_NO_INTERRUPT virtual |
| 3492 | 3.11a7 | Make POP_JUMP_IF_NONE, NOT_NONE, TRUE and FALSE relative |
| 3493 | 3.11a7 | Make JUMP_IF_TRUE_OR_POP and JUMP_IF_FALSE_OR_POP relative |
| 3494 | 3.11a7 | New location info table |
| 3495 | 3.11b4, final | Set the line number of the module’s RESUME instruction to 0, per PEP 626 |
| 3500 | 3.12a1 | Remove PRECALL |
| 3501 | 3.12a1 | YIELD_VALUE’s argument is the stack depth |
| 3502 | 3.12a1 | LOAD_FAST_CHECK; LOAD_FAST no longer checks for NULL |
| 3503 | 3.12a1 | Shrink the LOAD_METHOD cache |
| 3504 | 3.12a1 | Merge LOAD_METHOD back into LOAD_ATTR |
| 3505 | 3.12a1 | Specialisation and a cache for FOR_ITER |
| 3506 | 3.12a1 | Add BINARY_SLICE and STORE_SLICE |
| 3507 | 3.12a1 | Set the line number of the module’s RESUME to 0 |
| 3508 | 3.12a1 | Add CLEANUP_THROW |
| 3509 | 3.12a1 | Conditional jumps only jump forward |
| 3510 | 3.12a2 | FOR_ITER leaves the iterator on the stack |
| 3511 | 3.12a2 | Add the STOPITERATION_ERROR instruction |
| 3512 | 3.12a2 | Remove all unused constants from code objects |
| 3513 | 3.12a4 | Add CALL_INTRINSIC_1; remove STOPITERATION_ERROR, PRINT_EXPR and IMPORT_STAR |
| 3514 | 3.12a4 | Remove ASYNC_GEN_WRAP, LIST_TO_TUPLE and UNARY_POSITIVE |
| 3515 | 3.12a5 | Embed a jump mask in COMPARE_OP’s argument |
| 3516 | 3.12a5 | Add COMPARE_AND_BRANCH |
| 3517 | 3.12a5 | Change YIELD_VALUE’s argument to the exception block depth |
| 3518 | 3.12a6 | Add RETURN_CONST |
| 3519 | 3.12a6 | Modify SEND |
| 3520 | 3.12a6 | Remove PREP_RERAISE_STAR, add CALL_INTRINSIC_2 |
| 3521 | 3.12a7 | Shrink the LOAD_GLOBAL caches |
| 3522 | 3.12a7 | Remove JUMP_IF_FALSE_OR_POP and JUMP_IF_TRUE_OR_POP |
| 3523 | 3.12a7 | Convert COMPARE_AND_BRANCH back to COMPARE_OP |
| 3524 | 3.12a7 | Shrink the BINARY_SUBSCR caches |
| 3525 | 3.12b1 | Shrink the CALL caches |
| 3526 | 3.12b1 | Add instrumentation support |
| 3527 | 3.12b1 | Add LOAD_SUPER_ATTR |
| 3528 | 3.12b1 | Add the LOAD_SUPER_ATTR_METHOD specialisation |
| 3529 | 3.12b1 | Inline list, dict and set comprehensions |
| 3530 | 3.12b1 | Shrink the LOAD_SUPER_ATTR caches |
| 3531 | 3.12b1, final | Add PEP 695 changes |
| 3550 | 3.13a1 | Plugin optimizer support |
| 3551 | 3.13a1 | Compact superinstructions |
| 3552 | 3.13a1 | Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST |
| 3553 | 3.13a1 | Add SET_FUNCTION_ATTRIBUTE |
| 3554 | 3.13a1 | More efficient bytecodes for f-strings |
| 3555 | 3.13a1 | Generate specialised opcode metadata from bytecodes.c |
| 3556 | 3.13a1 | Convert LOAD_CLOSURE to a pseudo-instruction |
| 3557 | 3.13a1 | Make the conversion to boolean in jumps explicit |
| 3558 | 3.13a1 | Reorder the stack items for CALL |
| 3559 | 3.13a1 | Generate opcode numbers from bytecodes.c |
| 3560 | 3.13a1 | Add RESUME_CHECK |
| 3561 | 3.13a1 | Add a cache entry to branch instructions |
| 3562 | 3.13a1 | Assign numbers for internal instructions in a separate range |
| 3563 | 3.13a1 | Add CALL_KW, remove KW_NAMES |
| 3564 | 3.13a1 | Remove YIELD_VALUE’s argument, change RESUME’s argument values |
| 3565 | 3.13a1 | YIELD_VALUE’s argument says whether it is in a yield-from |
| 3566 | 3.13a1 | Emit JUMP_NO_INTERRUPT instead of JUMP for non-loop cases without a line number |
| 3567 | 3.13a1 | Reimplement line number propagation by the compiler |
| 3568 | 3.13a1 | Change the meaning of END_FOR |
| 3569 | 3.13a5 | Specialise CONTAINS_OP |
| 3570 | 3.13a6 | Add the __firstlineno__ class attribute |
| 3571 | 3.13b1, final | Fix the miscompilation of private names in generic classes |
| 3600 | 3.14a1 | Add LOAD_COMMON_CONSTANT |
| 3601 | 3.14a1 | Fix the miscompilation of private names in generic classes |
| 3602 | 3.14a1 | Add LOAD_SPECIAL; remove BEFORE_WITH and BEFORE_ASYNC_WITH |
| 3603 | 3.14a1 | Remove BUILD_CONST_KEY_MAP |
| 3604 | 3.14a1 | Do not duplicate the test at the end of while statements |
| 3605 | 3.14a1 | Move ENTER_EXECUTOR to 255 |
| 3606 | 3.14a1 | Specialise CALL_KW |
| 3607 | 3.14a1 | Add the pseudo-instructions JUMP_IF_TRUE and JUMP_IF_FALSE |
| 3608 | 3.14a1 | Add support for slices |
| 3609 | 3.14a2 | Add LOAD_SMALL_INT and LOAD_CONST_IMMORTAL; remove RETURN_CONST |
| 3610 | 3.14a4 | Add the VALUE_WITH_FAKE_GLOBALS format to annotationlib |
| 3611 | 3.14a4 | Add NOT_TAKEN |
| 3612 | 3.14a4 | Add POP_ITER and INSTRUMENTED_POP_ITER |
| 3613 | 3.14a4 | Add LOAD_CONST_MORTAL |
| 3614 | 3.14a5 | Add BINARY_OP_EXTEND |
| 3615 | 3.14a5 | CALL_FUNCTION_EX always takes a kwargs argument |
| 3616 | 3.14a5 | Remove BINARY_SUBSCR and its family, making them BINARY_OPs |
| 3617 | 3.14a6 | Branch monitoring for async for loops |
| 3618 | 3.14a6 | Add an argument to END_ASYNC_FOR |
| 3619 | 3.14a6 | Renumber RESUME from 149 to 128 |
| 3620 | 3.14a6 | Optimise bytecode for all, any and tuple called on a generator expression |
| 3621 | 3.14a7 | Optimise LOAD_FAST instructions into LOAD_FAST_BORROW |
| 3622 | 3.14a7 | Store annotations in different class dict keys |
| 3623 | 3.14a7 | Add BUILD_INTERPOLATION and BUILD_TEMPLATE |
| 3624 | 3.14b1 | Do not optimise LOAD_FAST when the local is killed by DELETE_FAST |
| 3625 | 3.14b3 | Fix handling of instructions that may leave operands on the stack when optimising LOAD_FAST |
| 3626 | 3.14rc2 | Fix missing exception handlers in logical expressions |
| 3627 | 3.14rc3, final | Fix the miscompilation of some module-level annotations |
| 3650 | 3.15a0 | Initial version |
| 3651 | 3.15a1 | Simplify LOAD_CONST |
| 3652 | 3.15a1 | Virtual iterators |
| 3653 | 3.15a1 | Fix handling of instructions that may leave operands on the stack when optimising LOAD_FAST |
| 3654 | 3.15a1 | Fix missing exception handlers in logical expressions |
| 3655 | 3.15a1 | Fix the miscompilation of some module-level annotations |
| 3656 | 3.15a1 | Add TRACE_RECORD, for platforms with a switch-based interpreter |
| 3657 | 3.15a4 | Add BINARY_OP_SUBSCR_USTR_INT |
| 3658 | 3.15a4 | Optimise bytecode for list and set called on a generator expression |
| 3659 | 3.15a4 | Add CALL_FUNCTION_EX specialisation |
| 3660 | 3.15a4 | Change the generator preamble code |
| 3661 | 3.15a4 | Lazy imports: IMPORT_NAME changes |
| 3662 | 3.15a8 | Add a counter to RESUME |
| 3663 | 3.15a8 | Merge GET_ITER and GET_YIELD_FROM_ITER; modify SEND to make it more like FOR_ITER |
| 3664 | 3.15a8 | Fix __qualname__ for __annotate__ functions |
| 3665 | 3.15a8 | Add FOR_ITER_VIRTUAL and GET_ITER specialisations |
| 3666 | 3.15b1, final | Add SEND_VIRTUAL and SEND_ASYNC_GEN specialisations |