全くよく解らないので、ソースを見てみる
http://www-06.ibm.com/jp/developerworks/linux/030425/j_l-pymeta.html
Versionは2.5.1 http://svn.python.org/view/python/tags/r251/ から落としてくる
__metaclass__ でgrepすると
などが見つかる
Python/ceval.c:4060
static PyObject *
build_class(PyObject *methods, PyObject *bases, PyObject *name)
{
build_class はPythonバイトコード命令の BUILD_CLASS に対応している http://www.python.jp/doc/2.4/lib/bytecodes.html
- BUILD_CLASS
- 新しいクラスオブジェクトを作成します。TOSはメソッド辞書、TOS1は基底クラスの名前のタプル、TOS2はクラス名です。
PyObject *metaclass = NULL, *result, *base;
if (PyDict_Check(methods))
metaclass = PyDict_GetItemString(methods, "__metaclass__");
if (metaclass != NULL)
Py_INCREF(metaclass);
else if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
base = PyTuple_GET_ITEM(bases, 0);
metaclass = PyObject_GetAttrString(base, "__class__");
if (metaclass == NULL) {
PyErr_Clear();
metaclass = (PyObject *)base->ob_type;
Py_INCREF(metaclass);
}
}
else {
PyObject *g = PyEval_GetGlobals();
if (g != NULL && PyDict_Check(g))
metaclass = PyDict_GetItemString(g, "__metaclass__");
if (metaclass == NULL)
metaclass = (PyObject *) &PyClass_Type;
Py_INCREF(metaclass);
}
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods, NULL);
Py_DECREF(metaclass);
if (result == NULL && PyErr_ExceptionMatches(PyExc_TypeError)) {
...
}
return result;
}
metaclass は
クラスの __metaclass__ を代入
1つ目のスパークラスの __class__ を代入 なければ、1つ目のスパークラスの ob_type を代入
Global(module)の __metaclass__ を代入
PyClass_Type を代入
が入る。 __metaclass__ を記述するということは、このステップを操作すること。
Py_INCREF, Py_DECREF は参照カウンタのインクリメント/デクリメント。 http://www.python.jp/doc/2.4/ext/refcountsInPython.html
http://www.python.jp/doc/2.4/api/type-structs.html
PyTypeObject* ob_type
型自体の型、別の言い方をするとメタタイプです。 PyObject_HEAD_INIT マクロで初期化され、通常は &PyType_Type になります。 Python 2.2.1 およびそれ以降では基底クラスの ob_type フィールドに初期化します。 ob_type が非ゼロの場合、PyType_Ready() は このフィールドを変更しません。 2.2.1 と 2.3 以降では、サブタイプはこのフィールドを継承します。
Objects/classobject.c:423
PyTypeObject PyClass_Type = {
PyObject_HEAD_INIT(&PyType_Type)
...
};
http://www.python.jp/doc/2.4/ext/dnt-basics.html
- PyObject_HEAD_INIT(&PyType_Type)
- この場合、タイプオブジェクトの型は「type」という名前になります
