PyCodeObjectを書き換える
Pythonのcodeオブジェクトを書き換えてしまう拡張ライブラリ「CodeHack」を作りました。
下の使用例では、関数の中の加算命令を乗算命令に書き換えています。
import CodeHack def f(x): print x + 2 f(10) #-> 12 # replace ADD to MULTIPLY code = f.func_code.co_code code = code.replace("\x17", "\x14") CodeHack.set_co_code(f.func_code, code) f(10) #-> 20
Pythonの拡張ライブラリを作って公開するのも初めてですし、 C言語をさわるのも数年ぶりなのですが、 想像以上に簡単でした。 全部distutilsがやってくれるので、 コンパイラを自分で呼ぶ必要すらありませんでした。 see Python モジュールの配布。
ダウンロード
(22:31にバージョン0.02を公開しました。0.01はたまにPythonが異常終了します。)CodeHack-0.0.2.win32.exe(Windows用インストーラ)
CodeHack-0.02.zip(ソースコード)
原理
原理はとても簡単(原理と言うほどでもないくらい簡単)です。 コードオブジェクトのco_code属性はリードオンリーフラグが立っているためにPythonのプログラムで直接書き換えることはできませんが、 Cのコードから書き換えることは可能です。 そこで、コードオブジェクトと文字列を受け取って、co_codeを書き換えてしまうモジュールをCで書きました。#include <Python.h> static PyObject * codehack(PyObject *self, PyObject *args) { PyObject* c; // PyCodeObject PyObject* s; // PyString if (!PyArg_ParseTuple(args, "OO", &c, &s)) return NULL; PyCodeObject* code = (PyCodeObject*) c; Py_INCREF(s); code->co_code = s; Py_RETURN_NONE; } static PyMethodDef Methods[] = { {"set_co_code", codehack, METH_VARARGS, "overwrite co_code"}, {NULL, NULL, 0, NULL} }; PyMODINIT_FUNC initCodeHack(void) { (void) Py_InitModule("CodeHack", Methods); }