Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Bộ gỡ mã bytecode Python (dis)


Mô-đun dis trong thư viện chuẩn Python cung cấp các hàm hữu ích để phân tích bytecode Python bằng cách gỡ mã (disassemble) nó thành dạng đọc được bởi con người. Điều này giúp thực hiện các tối ưu hóa. Bytecode là chi tiết triển khai phụ thuộc vào phiên bản của trình thông dịch.

Hàm dis()

Hàm dis() tạo biểu diễn gỡ mã của bất kỳ mã nguồn Python nào: mô-đun, lớp, phương thức, hàm, hoặc đối tượng code.

>>> def hello():
...     print("hello world")
>>> import dis
>>> dis.dis(hello)
  2           0 LOAD_GLOBAL              0 (print)
              3 LOAD_CONST               1 ('hello world')
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 POP_TOP
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

API phân tích bytecode được định nghĩa trong lớp Bytecode. Constructor của nó trả về đối tượng Bytecode có các phương thức sau để phân tích bytecode:

Bytecode()

Đây là constructor. Phân tích bytecode tương ứng với một hàm, generator, phương thức, chuỗi mã nguồn, hoặc đối tượng code. Đây là trình bao bọc tiện lợi cho nhiều hàm.

>>> string = dis.Bytecode(hello)
>>> for x in string:
...     print(x)
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='print', argrepr='print', offset=0, starts_line=2, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval='hello world', argrepr="'hello world'", offset=3, starts_line=None, is_jump_target=False)
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='1 positional, 0 keyword pair', offset=6, starts_line=None, is_jump_target=False)
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=9, starts_line=None, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=10, starts_line=None, is_jump_target=False)
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=13, starts_line=None, is_jump_target=False)

code_info()

Hàm này trả về thông tin của đối tượng code Python.

>>> dis.code_info(hello)
"Name: hello\nFilename: <pyshell#2>\nArgument count: 0\nKw-only arguments: 0\nNumber of locals: 0\nStack size: 2\nFlags: OPTIMIZED, NEWLOCALS, NOFREE\nConstants:\n 0: None\n 1: 'hello world'\nNames:\n 0: print"

show_code()

Hàm này in thông tin code chi tiết của mô-đun, hàm hoặc lớp Python.

>>> dis.show_code(hello)
Name: hello
Filename: <pyshell#2>
Argument count: 0
Kw-only arguments: 0
Number of locals: 0
Stack size: 2
Flags: OPTIMIZED, NEWLOCALS, NOFREE
Constants:
  0: None
  1: 'hello world'
Names:
  0: print

disassemble()

Hàm này gỡ mã một đối tượng code và cho đầu ra chia thành các cột sau:

  • số dòng, cho lệnh đầu tiên của mỗi dòng
  • lệnh hiện tại, chỉ ra bằng -->
  • lệnh có nhãn, chỉ ra bằng >>
  • địa chỉ của lệnh
  • tên mã phép toán
  • tham số phép toán
  • giải thích tham số trong ngoặc đơn.
>>> codeInString = 'a = 5\nb = 6\nsum = a + b \nprint("sum = ",sum)'
>>> codeObject = compile(codeInString, 'sumstring', 'exec')
>>> dis.disassemble(codeObject)

Đầu ra

1           0 LOAD_CONST               0 (5)
              3 STORE_NAME               0 (a)
2           6 LOAD_CONST               1 (6)
              9 STORE_NAME               1 (b)
3          12 LOAD_NAME                0 (a)
             15 LOAD_NAME                1 (b)
             18 BINARY_ADD
             19 STORE_NAME               2 (sum)
4          22 LOAD_NAME                3 (print)
             25 LOAD_CONST               2 ('sum =')
             28 LOAD_NAME                2 (sum)
             31 CALL_FUNCTION            2 (2 positional, 0 keyword pair)
             34 POP_TOP
             35 LOAD_CONST               3 (None)
             38 RETURN_VALUE

get_instructions()

Hàm này trả về một iterator qua các lệnh trong hàm, phương thức, chuỗi mã nguồn hoặc đối tượng code được cung cấp. Iterator tạo ra một chuỗi các named tuple Instruction đưa ra chi tiết của mỗi phép toán trong mã cung cấp.

>>> it = dis.get_instructions(code)
>>> for i in it:
...     print(i)
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=, argrepr='', offset=0, starts_line=2, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval='hello', argrepr="'hello'", offset=3, starts_line=None, is_jump_target=False)
Instruction(opname='MAKE_FUNCTION', opcode=132, arg=0, argval=0, argrepr='', offset=6, starts_line=None, is_jump_target=False)
Instruction(opname='STORE_NAME', opcode=90, arg=0, argval='hello', argrepr='hello', offset=9, starts_line=None, is_jump_target=False)
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=None, argrepr='None', offset=12, starts_line=None, is_jump_target=False)
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=15, starts_line=None, is_jump_target=False)

Thông tin hàm ở dạng đối tượng giống tuple với các tham số như sau:

InstructionChi tiết cho một phép toán bytecode
opcodemã số cho phép toán, tương ứng với giá trị opcode liệt kê dưới và giá trị bytecode trong bộ sưu tập Opcode.
opnametên đọc được bởi con người cho phép toán
argđối số số cho phép toán (nếu có), nếu không thì None
argvalgiá trị arg đã giải quyết (nếu biết), nếu không giống như arg
argreprmô tả đọc được bởi con người của đối số phép toán
offsetchỉ số bắt đầu của phép toán trong chuỗi bytecode
starts_linedòng bắt đầu bởi opcode này (nếu có), nếu không thì None
is_jump_targetTrue nếu code khác nhảy đến đây, nếu không thì False