Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Python

ดิแอสเซมเบลเลอร์สำหรับไบต์โค้ด Python (dis)

โมดูล dis ในไลบรารีมาตรฐานของ Python มีฟังก์ชันต่างๆ ที่มีประโยชน์สำหรับการวิเคราะห์ไบต์โค้ดของ Python โดยการดิแอสเซมเบล (disassemble) มันเป็นรูปแบบที่มนุษย์อ่านได้ นี่ช่วยให้ทำการเพิ่มประสิทธิภาพได้ ไบต์โค้ดเป็นรายละเอียดการใช้งานเฉพาะเวอร์ชันของตัวแปล

ฟังก์ชัน dis()

ฟังก์ชัน dis() สร้างการแสดงผลดิแอสเซมเบลของโค้ดต้นทาง Python ใดๆ เช่น โมดูล, คลาส, เมธอด, ฟังก์ชัน, หรืออ็อบเจ็กต์โค้ด:

>>> 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 การวิเคราะห์ไบต์โค้ดถูกกำหนดในคลาส Bytecode คอนสตรัคเตอร์คืนค่าอ็อบเจ็กต์ Bytecode ซึ่งมีเมธอดต่อไปนี้สำหรับวิเคราะห์ไบต์โค้ด:

Bytecode()

นี่คือคอนสตรัคเตอร์ วิเคราะห์ไบต์โค้ดที่สอดคล้องกับฟังก์ชัน, เจเนอเรเตอร์, เมธอด, สตริงโค้ดต้นทาง, หรืออ็อบเจ็กต์โค้ด นี่เป็นวอร์ปเปอร์ที่สะดวกสำหรับฟังก์ชันหลายตัว:

>>> 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()

ฟังก์ชันนี้คืนค่าข้อมูลของอ็อบเจ็กต์โค้ด Python:

>>> dis.code_info(hello)
"Name: hello\nFilename: \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()

ฟังก์ชันนี้พิมพ์ข้อมูลโค้ดโดยละเอียดของโมดูล, ฟังก์ชัน หรือคลาส Python:

>>> dis.show_code(hello)
Name: hello
Filename: 
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()

ฟังก์ชันนี้ดิแอสเซมเบลอ็อบเจ็กต์โค้ดและให้เอาต์พุทแบ่งในคอลัมน์ต่อไปนี้:

  • หมายเลขบรรทัด สำหรับคำสั่งแรกของแต่ละบรรทัด

  • คำสั่งปัจจุบัน แสดงด้วย -->

  • คำสั่งที่มีป้ายกำกับ แสดงด้วย >>

  • ที่อยู่ของคำสั่ง

  • ชื่อโค้ดการดำเนินการ (operation code name)

  • พารามิเตอร์การดำเนินการ

  • การตีความพารามิเตอร์ในวงเล็บ

>>> codeInString = 'a = 5\nb = 6\nsum = a + b \nprint("sum = ",sum)'
>>> codeObject = compile(codeInString, 'sumstring', 'exec')
>>> dis.disassemble(codeObject)

ผลลัพธ์

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()

ฟังก์ชันนี้คืนค่า iterator บนคำสั่งในฟังก์ชัน, เมธอด, สตริงโค้ดต้นทาง หรืออ็อบเจ็กต์โค้ดที่ให้มา Iterator สร้างชุดของ named tuples Instruction ให้รายละเอียดของแต่ละการดำเนินการในโค้ดที่ให้มา:

>>> it = dis.get_instructions(code)
>>> for i in it:
...     print(i)
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=", line 2>, argrepr='", line 2>', 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)

ข้อมูลฟังก์ชันอยู่ในรูปแบบ tuple-like object พร้อมพารามิเตอร์ดังนี้:

Instruction รายละเอียดสำหรับการดำเนินการไบต์โค้ด
opcode รหัสตัวเลขสำหรับการดำเนินการ สอดคล้องกับค่า opcode ที่แสดงด้านล่างและค่าไบต์โค้ดในคอลเลกชัน Opcode
opname ชื่อที่มนุษย์อ่านได้สำหรับการดำเนินการ
arg อาร์กิวเมนต์ตัวเลขสำหรับการดำเนินการ (ถ้ามี) มิฉะนั้น None
argval ค่า arg ที่แก้ไขแล้ว (ถ้ารู้) มิฉะนั้นเหมือน arg
argrepr คำอธิบายที่มนุษย์อ่านได้ของอาร์กิวเมนต์การดำเนินการ
offset ดัชนีเริ่มต้นของการดำเนินการภายในลำดับไบต์โค้ด
starts_line บรรทัดที่เริ่มต้นโดย opcode นี้ (ถ้ามี) มิฉะนั้น None
is_jump_target True หากโค้ดอื่นกระโดดมาที่นี่ มิฉะนั้น False