Is there any way to know by which Python version the .pyc
file was compiled?
pyc files are created by the Python interpreter when a . py file is imported. They contain the "compiled bytecode" of the imported module/program so that the "translation" from source code to bytecode (which only needs to be done once) can be skipped on subsequent imports if the . pyc is newer than the corresponding .
When a Python source file (module) is imported during an execution for the first time, the appropriate . pyc file is created automatically. If the same module is imported again, then the already created . pyc file is used.
pyc file contains the bytecode of your program. We get bytecode after compilation of . py file (source code). . pyc files are not created for all the files that you run.
pyc files are placed in the same directory as the . py file. In Python 3.2, the compiled files are placed in a __pycache__ subdirectory, and are named differently depending on which Python interpreter created them. (This can be useful to people importing the same Python modules from multiple versions of Python.)
The first two bytes of the .pyc
file are the magic number that tells the version of the bytecodes. The word is stored in little-endian format, and the known values are:
Python version | Decimal | Hexadecimal | Comment |
---|---|---|---|
Python 1.5 | 20121 | 0x994e | |
Python 1.5.1 | 20121 | 0x994e | |
Python 1.5.2 | 20121 | 0x994e | |
Python 1.6 | 50428 | 0x4cc4 | |
Python 2.0 | 50823 | 0x87c6 | |
Python 2.0.1 | 50823 | 0x87c6 | |
Python 2.1 | 60202 | 0x2aeb | |
Python 2.1.1 | 60202 | 0x2aeb | |
Python 2.1.2 | 60202 | 0x2aeb | |
Python 2.2 | 60717 | 0x2ded | |
Python 2.3a0 | 62011 | 0x3bf2 | |
Python 2.3a0 | 62021 | 0x45f2 | |
Python 2.3a0 | 62011 | 0x3bf2 | ! |
Python 2.4a0 | 62041 | 0x59f2 | |
Python 2.4a3 | 62051 | 0x63f2 | |
Python 2.4b1 | 62061 | 0x6df2 | |
Python 2.5a0 | 62071 | 0x77f2 | |
Python 2.5a0 | 62081 | 0x81f2 | ast-branch |
Python 2.5a0 | 62091 | 0x8bf2 | with |
Python 2.5a0 | 62092 | 0x8cf2 | changed WITH_CLEANUP opcode |
Python 2.5b3 | 62101 | 0x95f2 | fix wrong code: for x, in ...
|
Python 2.5b3 | 62111 | 0x9ff2 | fix wrong code: x += yield
|
Python 2.5c1 | 62121 | 0xa9f2 | fix wrong lnotab with for loops and storing constants that should have been removed |
Python 2.5c2 | 62131 | 0xb3f2 | fix wrong code: for x, in ... in listcomp/genexp |
Python 2.6a0 | 62151 | 0xc7f2 | peephole optimizations and STORE_MAP opcode |
Python 2.6a1 | 62161 | 0xd1f2 |
WITH_CLEANUP optimization |
Python 2.7a0 | 62171 | 0xdbf2 | optimize list comprehensions/change LIST_APPEND
|
Python 2.7a0 | 62181 | 0xe5f2 | optimize conditional branches: introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE
|
Python 2.7a0 | 62191 | 0xeff2 | introduce SETUP_WITH
|
Python 2.7a0 | 62201 | 0xf9f2 | introduce BUILD_SET
|
Python 2.7a0 | 62211 | 0x03f3 | introduce MAP_ADD and SET_ADD
|
Python 3000 | 3000 | 0xb80b | |
3010 | 0xc20b | removed UNARY_CONVERT
|
|
3020 | 0xcc0b | added BUILD_SET
|
|
3030 | 0xd60b | added keyword-only parameters | |
3040 | 0xe00b | added signature annotations | |
3050 | 0xea0b |
print becomes a function |
|
3060 | 0xf40b | PEP 3115 metaclass syntax | |
3061 | 0xf50b | string literals become unicode | |
3071 | 0xff0b | PEP 3109 raise changes | |
3081 | 0x090c | PEP 3137 make __file__ and __name__ unicode |
|
3091 | 0x130c | kill str8 interning | |
3101 | 0x1d0c | merge from 2.6a0, see 62151 | |
3103 | 0x1f0c |
__file__ points to source file |
|
Python 3.0a4 | 3111 | 0x270c |
WITH_CLEANUP optimization |
Python 3.0a5 | 3131 | 0x3b0c | lexical exception stacking, including POP_EXCEPT
|
Python 3.1a0 | 3141 | 0x450c | optimize list, set and dict comprehensions: change LIST_APPEND and SET_ADD , add MAP_ADD
|
Python 3.1a0 | 3151 | 0x4f0c | optimize conditional branches: introduce POP_JUMP_IF_FALSE and POP_JUMP_IF_TRUE
|
Python 3.2a0 | 3160 | 0x580c | add SETUP_WITH , tag: cpython-32 |
Python 3.2a1 | 3170 | 0x620c | add DUP_TOP_TWO , remove DUP_TOPX and ROT_FOUR , tag: cpython-32 |
Python 3.2a2 | 3180 | 0x6c0c | add DELETE_DEREF
|
Sources:
You can get the magic number of your Python as follows:
$ python -V
Python 2.6.2
# python
>>> import imp
>>> imp.get_magic().encode('hex')
'd1f20d0a'
To get the magic number for a pyc file you can do the following:
>>> f = open('test25.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'b3f20d0a'
>>> f = open('test26.pyc')
>>> magic = f.read(4)
>>> magic.encode('hex')
'd1f20d0a'
By comparing the magic numbers you'll know the python version that generated the pyc file.
Or, if you have a GNU/Linux system you can use the command "file" in a terminal:
$ file code.pyc
> code.pyc: python 3.5.2 byte-compiled
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With