Pythonでバイトコードを書き換える

Pythonでバイトコードを書き換える方法。co_codeがreadonlyなのでcodeオブジェクトをわざわざ作り直している。
以下の例では乗算を累乗に変更している。

import new
import opcode

def hoge(n):
    return 2 * n

hoge(16) #=>32

piyo = hoge.func_code.co_code.replace(chr(opcode.opmap['BINARY_MULTIPLY']), chr(opcode.opmap['BINARY_POWER']))

code = new.code(
    hoge.func_code.co_argcount,
    hoge.func_code.co_nlocals,
    hoge.func_code.co_stacksize,
    hoge.func_code.co_flags,
    piyo,
    hoge.func_code.co_consts,
    hoge.func_code.co_names,
    hoge.func_code.co_varnames,
    hoge.func_code.co_filename,
    hoge.func_code.co_name,
    hoge.func_code.co_firstlineno,
    hoge.func_code.co_lnotab
)
func = new.function(
    code,
    hoge.func_globals,
    hoge.func_name,
    hoge.func_defaults,
    hoge.func_closure
)

func(16) #=>65536

newの代わりにtypesを使ってもよい。その辺りはお好みで。

import new
import types
new.code is types.CodeType #=>True
new.function is types.FunctionType #=>True