W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
你想通過將你的代碼反編譯成低級的字節(jié)碼來查看它底層的工作機(jī)制。
<span class="pre" style="box-sizing: border-box;">dis</span>
?模塊可以被用來輸出任何Python函數(shù)的反編譯結(jié)果。例如:
>>> def countdown(n):
... while n > 0:
... print('T-minus', n)
... n -= 1
... print('Blastoff!')
...
>>> import dis
>>> dis.dis(countdown)
...
>>>
當(dāng)你想要知道你的程序底層的運行機(jī)制的時候,<span class="pre" style="box-sizing: border-box;">dis</span>
?模塊是很有用的。比如如果你想試著理解性能特征。 被?<span class="pre" style="box-sizing: border-box;">dis()</span>
?函數(shù)解析的原始字節(jié)碼如下所示:
>>> 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"
>>>
如果你想自己解釋這段代碼,你需要使用一些在?<span class="pre" style="box-sizing: border-box;">opcode</span>
?模塊中定義的常量。例如:
>>> c = countdown.__code__.co_code
>>> import opcode
>>> opcode.opname[c[0]]
>>> opcode.opname[c[0]]
'SETUP_LOOP'
>>> opcode.opname[c[3]]
'LOAD_FAST'
>>>
奇怪的是,在?<span class="pre" style="box-sizing: border-box;">dis</span>
?模塊中并沒有函數(shù)讓你以編程方式很容易的來處理字節(jié)碼。 不過,下面的生成器函數(shù)可以將原始字節(jié)碼序列轉(zhuǎn)換成?<span class="pre" style="box-sizing: border-box;">opcodes</span>
?和參數(shù)。
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)
這種方式很少有人知道,你可以利用它替換任何你想要替換的函數(shù)的原始字節(jié)碼。 下面我們用一個示例來演示整個過程:
>>> 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
你可以像這樣耍大招讓解釋器奔潰。但是,對于編寫更高級優(yōu)化和元編程工具的程序員來講, 他們可能真的需要重寫字節(jié)碼。本節(jié)最后的部分演示了這個是怎樣做到的。你還可以參考另外一個類似的例子:?this code on ActiveState
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: