コーディング過程をLingrで中継 [Main] Python拡張の作り方

[C(2)]Python拡張の作り方

コーディング過程をLingrで中継[Python(18)]Python拡張の作り方

[下を行け(3)]PythonのバイトコードをGRINEditで可視化

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);
}