9.25 拆解Pythonå—节ç �¶
问题¶
ä½ æƒ³é€šè¿‡å°†ä½ çš„ä»£ç �å��编译æˆ�低级的å—节ç �æ�¥æŸ¥çœ‹å®ƒåº•层的工作机制。
解决方案¶
dis 模��以被用�输出任何Python函数的�编译结果。例如:
>>> def countdown(n):
... while n > 0:
... print('T-minus', n)
... n -= 1
... print('Blastoff!')
...
>>> import dis
>>> dis.dis(countdown)
2 0 SETUP_LOOP 30 (to 32)
>> 2 LOAD_FAST 0 (n)
4 LOAD_CONST 1 (0)
6 COMPARE_OP 4 (>)
8 POP_JUMP_IF_FALSE 30
3 10 LOAD_GLOBAL 0 (print)
12 LOAD_CONST 2 ('T-minus')
14 LOAD_FAST 0 (n)
16 CALL_FUNCTION 2
18 POP_TOP
4 20 LOAD_FAST 0 (n)
22 LOAD_CONST 3 (1)
24 INPLACE_SUBTRACT
26 STORE_FAST 0 (n)
28 JUMP_ABSOLUTE 2
>> 30 POP_BLOCK
5 >> 32 LOAD_GLOBAL 0 (print)
34 LOAD_CONST 4 ('Blastoff!')
36 CALL_FUNCTION 1
38 POP_TOP
40 LOAD_CONST 0 (None)
42 RETURN_VALUE
>>>
讨论¶
å½“ä½ æƒ³è¦�知é�“ä½ çš„ç¨‹åº�底层的è¿�行机制的时候,dis 模å�—æ˜¯å¾ˆæœ‰ç”¨çš„ã€‚æ¯”å¦‚å¦‚æžœä½ æƒ³è¯•ç�€ç�†è§£æ€§èƒ½ç‰¹å¾�。
被 dis() 函数解æž�的原始å—节ç �如下所示:
>>> countdown.__code__.co_code
b"x'\x00|\x00\x00d\x01\x00k\x04\x00r)\x00t\x00\x00d\x02\x00|\x00\x00\x83
\x02\x00\x01|\x00\x00d\x03\x008}\x00\x00q\x03\x00Wt\x00\x00d\x04\x00\x83
\x01\x00\x01d\x00\x00S"
>>>
å¦‚æžœä½ æƒ³è‡ªå·±è§£é‡Šè¿™æ®µä»£ç �ï¼Œä½ éœ€è¦�使用一些在 opcode 模å�—ä¸å®šä¹‰çš„常é‡�。例如:
>>> c = countdown.__code__.co_code
>>> import opcode
>>> opcode.opname[c[0]]
'SETUP_LOOP'
>>> opcode.opname[c[2]]
'LOAD_FAST'
>>>
奇怪的是,在 dis 模å�—ä¸å¹¶æ²¡æœ‰å‡½æ•°è®©ä½ 以编程方å¼�很容易的æ�¥å¤„ç�†å—节ç �。
ä¸�过,下é�¢çš„生æˆ�器函数å�¯ä»¥å°†åŽŸå§‹å—节ç �åº�列转æ�¢æˆ� opcodes å’Œå�‚数。
import opcode
def generate_opcodes(codebytes):
extended_arg = 0
i = 0
n = len(codebytes)
while i < n:
op = codebytes[i]
i += 1
if op >= opcode.HAVE_ARGUMENT:
oparg = codebytes[i] + codebytes[i+1]*256 + extended_arg
extended_arg = 0
i += 2
if op == opcode.EXTENDED_ARG:
extended_arg = oparg * 65536
continue
else:
oparg = None
yield (op, oparg)
使用方法如下:
>>> for op, oparg in generate_opcodes(countdown.__code__.co_code):
... print(op, opcode.opname[op], oparg)
è¿™ç§�æ–¹å¼�很少有人知é�“ï¼Œä½ å�¯ä»¥åˆ©ç”¨å®ƒæ›¿æ�¢ä»»ä½•ä½ æƒ³è¦�替æ�¢çš„函数的原始å—节ç �。 下é�¢æˆ‘们用一个示例æ�¥æ¼”示整个过程:
>>> def add(x, y):
... return x + y
...
>>> c = add.__code__
>>> c
<code object add at 0x1007beed0, file "<stdin>", line 1>
>>> c.co_code
b'|\x00\x00|\x01\x00\x17S'
>>>
>>> # Make a completely new code object with bogus byte code
>>> import types
>>> newbytecode = b'xxxxxxx'
>>> nc = types.CodeType(c.co_argcount, c.co_kwonlyargcount,
... c.co_nlocals, c.co_stacksize, c.co_flags, newbytecode, c.co_consts,
... c.co_names, c.co_varnames, c.co_filename, c.co_name,
... c.co_firstlineno, c.co_lnotab)
>>> nc
<code object add at 0x10069fe40, file "<stdin>", line 1>
>>> add.__code__ = nc
>>> add(2,3)
Segmentation fault
ä½ å�¯ä»¥åƒ�è¿™æ ·è€�大招让解释器奔溃。但是,对于编写更高级优化和元编程工具的程åº�员æ�¥è®²ï¼Œ 他们å�¯èƒ½çœŸçš„需è¦�é‡�写å—节ç �。本节最å�Žçš„éƒ¨åˆ†æ¼”ç¤ºäº†è¿™ä¸ªæ˜¯æ€Žæ ·å�šåˆ°çš„ã€‚ä½ è¿˜å�¯ä»¥å�‚考å�¦å¤–一个类似的例å�: this code on ActiveState