A Python module is automatically compiled into a .pyc file by CPython interpreter. The .pyc file, which contains the bytecode, is in binary format (marshaled code?). Is there a GUI (or command line) tool that let me view the bytecode?
Asked
Active
Viewed 2.5k times
15
-
Are you fine with importing the module? This would of course execute it. – Sven Marnach Jun 21 '12 at 15:23
-
Could you clarify "view the bytecode"? – Thomas Orozco Jun 21 '12 at 15:31
-
do you want to decompile it to python code (`.py`) or to understand what each byte means? – Nadir Sampaoli Jun 21 '12 at 15:33
-
1I would like to look at and study the bytecode. I especially wants to find out how module global objects are represented. – dividebyzero Jun 21 '12 at 15:34
-
Did a little google search and I found that Python comes with a module called "dis" that let me do that. "import dis; import mymodule; dis.dis(module)". Still wondering if there is a GUI tool for this. – dividebyzero Jun 21 '12 at 15:38
-
[python docs](http://docs.python.org/py3k/library/dis.html#bytecodes) also list some bytecode meanings. Also, why do you want a GUI instead of python's prompt? – Nadir Sampaoli Jun 21 '12 at 15:43
3 Answers
15
Every *.pyc file is a binary file containing next things:
- a four-byte magic number - it's simply bytes that change with each change to the marshalling code;
- a four-byte modification timestamp - is the Unix modification timestamp of the source file that generated the .pyc, so that it can be recompiled if the source changes;
- since version Python3.3+ next four bytes is field that encodes the size of the source file as a long;
- a marshalled code object.
Why not just use the CPython`s built-in features for this task?
A file view_pyc_file.py
import platform
import time
import sys
import binascii
import marshal
import dis
import struct
def view_pyc_file(path):
"""Read and display a content of the Python`s bytecode in a pyc-file."""
file = open(path, 'rb')
magic = file.read(4)
timestamp = file.read(4)
size = None
if sys.version_info.major == 3 and sys.version_info.minor >= 3:
size = file.read(4)
size = struct.unpack('I', size)[0]
code = marshal.load(file)
magic = binascii.hexlify(magic).decode('utf-8')
timestamp = time.asctime(time.localtime(struct.unpack('I', timestamp)[0]))
dis.disassemble(code)
print('-' * 80)
print(
'Python version: {}\nMagic code: {}\nTimestamp: {}\nSize: {}'
.format(platform.python_version(), magic, timestamp, size)
)
file.close()
if __name__ == '__main__':
view_pyc_file(sys.argv[1])
Tested with next CPython`s versions:
- 2.7.9
- 3.4.2
- 3.5.2
Demonstration
Content of a file main.py
$ cat main.py
print("Never give up")
Create and to read pyc-file by the python2.7
setivolkylany$~/Downloads/temp/temp$ python2.7 -m py_compile main.py
setivolkylany$~/Downloads/temp/temp$ python2.7 view_pyc_file.py ./main.pyc
1 0 LOAD_CONST 0 ('Never give up')
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 1 (None)
8 RETURN_VALUE
--------------------------------------------------------------------------------
Python version: 2.7.9
Magic code: 03f30d0a
Timestamp: Fri Mar 10 15:08:20 2017
Size: None
Create and to read pyc-file by the python3.4
setivolkylany$~/Downloads/temp/temp$ python3.4 -m py_compile main.py
setivolkylany$~/Downloads/temp/temp$ python3.4 view_pyc_file.py __pycache__/main.cpython-34.pyc
1 0 LOAD_NAME 0 (print)
3 LOAD_CONST 0 ('Never give up')
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
--------------------------------------------------------------------------------
Python version: 3.4.2
Magic code: ee0c0d0a
Timestamp: Fri Mar 10 15:08:20 2017
Size: 23
Create and to read pyc-file by the python3.5
setivolkylany$~/Downloads/temp/temp$ python3.5 -m py_compile main.py
setivolkylany$~/Downloads/temp/temp$ python3.5 view_pyc_file.py __pycache__/main.cpython-35.pyc
1 0 LOAD_NAME 0 (print)
3 LOAD_CONST 0 ('Never give up')
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 POP_TOP
10 LOAD_CONST 1 (None)
13 RETURN_VALUE
--------------------------------------------------------------------------------
Python version: 3.5.2
Magic code: 160d0d0a
Timestamp: Fri Mar 10 15:08:20 2017
Size: 23
Based on:
-
4This now needs to be updated with regards to https://www.python.org/dev/peps/pep-0552/ (Python 3.7). – Apteryx Apr 02 '19 at 20:18
-
2I am unable to add the required modification here in the comments, so I've added it as a new answer, but @PADYMKO please feel free to edit your answer with it. – powersource97 May 07 '21 at 03:27
6
Extending the code form @PADYMKO based on @Apteryx 's note about the PEP:
def view_pyc_file(path):
"""Read and display a content of the Python`s bytecode in a pyc-file."""
with open(path, 'rb') as file:
magic = file.read(4)
bit_field = None
timestamp = None
hashstr = None
size = None
if sys.version_info.major == 3 and sys.version_info.minor >= 7:
bit_field = int.from_bytes(file.read(4), byteorder=sys.byteorder)
if 1 & bit_field == 1:
hashstr = file.read(8)
else:
timestamp = file.read(4)
size = file.read(4)
size = struct.unpack('I', size)[0]
elif sys.version_info.major == 3 and sys.version_info.minor >= 3:
timestamp = file.read(4)
size = file.read(4)
size = struct.unpack('I', size)[0]
else:
timestamp = file.read(4)
code = marshal.load(file)
magic = binascii.hexlify(magic).decode('utf-8')
timestamp = time.asctime(time.localtime(struct.unpack('I', timestamp)[0]))
dis.disassemble(code)
print('-' * 80)
print(
'Python version: {}\nMagic code: {}\nTimestamp: {}\nSize: {}\nHash: {}\nBitfield: {}'
.format(platform.python_version(), magic, timestamp, size, hashstr, bit_field)
)

Elazar
- 20,415
- 4
- 46
- 67

powersource97
- 373
- 5
- 12
2
There's a visual python disassembler called PyChrisanthemum.
To do it the command-line way you can use module dis
(python 2.7.3, python 3.2.3), as OP already found out.

Nadir Sampaoli
- 5,437
- 4
- 22
- 32
-
This project is now pretty dead, so I wouldn't expect it to be able to read (perfectly) the byte-code produced by recent Python versions. – Apteryx Apr 02 '19 at 20:19