Pythonを読む
はじめに †
__build_class__が実行される様を見ていきます。以前にも見ましたが起点となるCALL_FUNCTION
1
2
3
4
5
6
7
8
9
10
11
12
| -
|
|
|
|
|
|
-
|
!
|
!
| TARGET(CALL_FUNCTION) {
PyObject **sp, *res;
PCALL(PCALL_ALL);
sp = stack_pointer;
res = call_function(&sp, oparg, NULL);
stack_pointer = sp;
PUSH(res);
if (res == NULL) {
goto error;
}
DISPATCH();
}
|
前はcall_functionの先は概要だけ説明しましたが今回はこの先についてガチに見ていきます。
call_function (Python/ceval.c) †
call_functionはバイトコード実行と同じceval.cに書かれています。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
-
|
|
|
|
|
|
|
-
|
!
-
|
|
|
|
|
|
!
-
-
!
-
|
|
!
-
|
|
|
!
!
| static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
stack = (*pp_stack) - nargs - nkwargs;
C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else {
}
assert((x != NULL) ^ (PyErr_Occurred() != NULL));
while ((*pp_stack) > pfunc) {
w = EXT_POP(*pp_stack);
Py_DECREF(w);
PCALL(PCALL_POP);
}
return x;
}
|
__build_class__の実装はCで書かれているので今回はifの部分が実行されます。
Cで実装された関数を実行する_PyCFunction_FastCallKeywordsについて見る前に、そろそろPyObjectについて見ていくことにしましょう。
PyObject (Include/object.h) †
PyObjectはその名の通りPythonオブジェクトのC表現です。
1
2
3
4
5
| -
|
|
|
!
| typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;
|
_PyObject_HEAD_EXTRAはデバッグオプション付きでビルドされたときのデバッグ情報用メンバなので今回は無視します。参照カウントとTypeObjectへの参照を持っているようです。
TypeObjectを見る前に、__build_class__はPyCFunctionObjectなわけですがこの定義がどうなっているかというと(Include/methodobject.hです)、
1
2
3
4
5
6
7
| -
|
|
|
|
|
!
| typedef struct {
PyObject_HEAD
PyMethodDef *m_ml;
PyObject *m_self;
PyObject *m_module;
PyObject *m_weakreflist;
} PyCFunctionObject;
|
PyObject_HEADの定義はInclude/object.hに戻って、
1
2
|
|
#define PyObject_HEAD PyObject ob_base;
|
つまり、PyCFunctionObjectの先頭部分はPyObjectということになります。Cに不慣れな方は「え?これ構造体の中に構造体埋め込まれてるけどfunc->ob_base.ob_refcntみたいにアクセスすんの?」と思われるかもしれませんが、そこはポインタマジック、ポインタ経由でアクセスするとぶっちゃけ以下のように定義されているのと同じようにアクセスできます。
1
2
3
4
5
6
7
8
| -
|
|
|
|
|
|
!
| typedef struct {
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
PyMethodDef *m_ml;
PyObject *m_self;
PyObject *m_module;
PyObject *m_weakreflist;
} PyCFunctionObject;
|
全てのオブジェクト表現が共通のヘッダを持っているため、操作をする際には共通要素に依存した処理が書けることになります。
ちなみに、PyCFunction_Checkの実装は以下の通りです。
1
|
| #define PyCFunction_Check(op) (Py_TYPE(op) == &PyCFunction_Type)
|
Py_TYPEはob_typeメンバを取り出すマクロです。
PyTypeObject (Include/object.h) †
さて次にPyTypeObjectです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
| -
|
|
|
|
|
|
|
|
|
|
-
!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
| typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name;
Py_ssize_t tp_basicsize, tp_itemsize;
destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async;
reprfunc tp_repr;
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
PyBufferProcs *tp_as_buffer;
unsigned long tp_flags;
const char *tp_doc;
traverseproc tp_traverse;
inquiry tp_clear;
richcmpfunc tp_richcompare;
Py_ssize_t tp_weaklistoffset;
getiterfunc tp_iter;
iternextfunc tp_iternext;
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
struct _typeobject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free;
inquiry tp_is_gc;
PyObject *tp_bases;
PyObject *tp_mro;
PyObject *tp_cache;
PyObject *tp_subclasses;
PyObject *tp_weaklist;
destructor tp_del;
unsigned int tp_version_tag;
destructor tp_finalize;
} PyTypeObject;
|
長い、ってところですがメンバについて詳しいことは次回以降に見ていきます。ともかく次にPyCFunction_Typeの定義を見てみましょう。Objects/methodobject.cです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
| -
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
!
| PyTypeObject PyCFunction_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"builtin_function_or_method",
sizeof(PyCFunctionObject),
0,
(destructor)meth_dealloc,
0,
0,
0,
0,
(reprfunc)meth_repr,
0,
0,
0,
(hashfunc)meth_hash,
PyCFunction_Call,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
0,
(traverseproc)meth_traverse,
0,
meth_richcompare,
offsetof(PyCFunctionObject, m_weakreflist),
0,
0,
meth_methods,
meth_members,
meth_getsets,
0,
0,
};
|
今回の本筋ではありませんが説明しないわけにもいかないので、PyCFunction_Typeはob_typeとしてPyType_Typeを参照します。つまり、「PyCFunctionはType型」ということになります。Type型は「型の型」、メタな型です。
で、ともかくPyCFunction型が定義されました。
PyObjectとPyTypeObjectの関連付け †
大体わかってきましたがPyTypeObjectはPyObjectの型を表すオブジェクトです。別の言語風に言うとクラスオブジェクトといったところでしょうか。一応、オブジェクトが生成されるときにPyTypeObjectが設定される様子を確認しておきましょう。前回は中に踏み込まなかったPyCFunction_NewEx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-
|
|
-
|
|
|
!
-
|
|
|
!
|
|
|
|
|
|
|
|
!
| PyObject *
PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module)
{
PyCFunctionObject *op;
op = free_list;
if (op != NULL) {
free_list = (PyCFunctionObject *)(op->m_self);
(void)PyObject_INIT(op, &PyCFunction_Type);
numfree--;
}
else {
op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type);
if (op == NULL)
return NULL;
}
op->m_weakreflist = NULL;
op->m_ml = ml;
Py_XINCREF(self);
op->m_self = self;
Py_XINCREF(module);
op->m_module = module;
_PyObject_GC_TRACK(op);
return (PyObject *)op;
}
|
PyObject_GC_New、Include/objimpl.hを経由して実体はModule/gcmodule.cの_PyObject_GC_New
1
2
3
4
5
6
7
|
-
|
|
|
|
!
| _PyObject_GC_New(PyTypeObject *tp)
{
PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp));
if (op != NULL)
op = PyObject_INIT(op, tp);
return op;
}
|
PyObject_INITはまたInclude/objimpl.hに戻ります。
1
2
|
| #define PyObject_INIT(op, typeobj) \
( Py_TYPE(op) = (typeobj), _Py_NewReference((PyObject *)(op)), (op) )
|
というわけでPyObjectとPyTypeObjectが関連付けられました。
_PyCFunction_FastCallKeywords (Objects/methodobject.c) †
長くなりましたがPyObjectについて確認できたのでオブジェクトの型がPyCFunction_Typeの時に実行される_PyCFunction_FastCallKeywordsに進みます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
-
|
|
|
-
!
|
-
|
-
|
!
!
-
|
!
|
|
|
|
!
| PyObject *
_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack,
Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *kwdict, *result;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
if (kwdict == NULL) {
return NULL;
}
}
else {
kwdict = NULL;
}
result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict);
Py_XDECREF(kwdict);
return result;
}
|
今回はnkwargsは0なのでそのまま_PyCFunction_FastCallDictへ。
長いので実行される部分以外は省略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
-
|
|
|
|
|
|
-
|
!
|
|
|
|
-
|
-
!
|
-
!
|
|
-
|
|
|
-
|
|
|
|
!
|
|
-
|
!
|
-
|
!
-
|
!
|
|
!
|
|
-
!
|
|
-
!
|
!
|
|
|
|
!
| PyObject *
_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs,
PyObject *kwargs)
{
PyCFunctionObject *func = (PyCFunctionObject*)func_obj;
PyCFunction meth = PyCFunction_GET_FUNCTION(func);
PyObject *self = PyCFunction_GET_SELF(func);
PyObject *result;
int flags;
flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST);
switch (flags)
{
case METH_NOARGS:
case METH_O:
case METH_VARARGS:
case METH_VARARGS | METH_KEYWORDS:
{
PyObject *tuple;
if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) {
PyErr_Format(PyExc_TypeError,
"%.200s() takes no keyword arguments",
func->m_ml->ml_name);
return NULL;
}
tuple = _PyStack_AsTuple(args, nargs);
if (tuple == NULL) {
return NULL;
}
if (flags & METH_KEYWORDS) {
result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs);
}
else {
result = (*meth) (self, tuple);
}
Py_DECREF(tuple);
break;
}
case METH_FASTCALL:
default:
PyErr_SetString(PyExc_SystemError,
"Bad call flags in PyCFunction_Call. "
"METH_OLDARGS is no longer supported!");
return NULL;
}
result = _Py_CheckFunctionResult(func_obj, result, NULL);
return result;
}
|
というわけで、Python関数に対応するC言語の関数が実行されることになります。この先は次回。
おわりに †
今回は関数実行をスタートにPyObjectについて見ていきました。
本当はPyTypeObjectについてもう少し触れようと思ったのですがC実装の関数の場合はTypeObectは識別子ぐらいにしか使われていないので省略しました。心配しなくても(?)後からがっつり見ていくことになります。
ともかくこれでようやく__build_class__に対するbuiltin___build_class__が実行される段階まで来ました。