Python/インスタンス生成
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Pythonを読む]]
#contents
*はじめに [#g26b6764]
PyObjectから入ったので長くなりましたがようやくクラスが作...
#code(Python){{
foo = Foo(123)
}}
対応するバイトコードこんな感じ。
9 14 LOAD_NAME 0 (Foo)
16 LOAD_CONST 2 (123)
18 CALL_FUNCTION 1
20 STORE_NAME 1 (foo)
*call_function (Python/ceval.c) [#e34fe680]
というわけでCALL_FUNCTIONに対応するcall_functionです。前...
#code(C){{
static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyO...
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_...
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
// こっちじゃない
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(fun...
/* optimize access to bound methods */
PyObject *self = PyMethod_GET_SELF(func);
PCALL(PCALL_METHOD);
PCALL(PCALL_BOUND_METHOD);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
}
else {
Py_INCREF(func);
}
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
else {
x = _PyObject_FastCallKeywords(func, stack, n...
}
Py_DECREF(func);
}
// 省略
return x;
}
}}
メソッド呼び出し用の加工処理っぽいことしてますがそれはま...
#code(C){{
PyObject *
_PyObject_FastCallKeywords(PyObject *func, PyObject **sta...
PyObject *kwnames)
{
PyObject *kwdict, *result;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_...
if (PyFunction_Check(func)) {
return _PyFunction_FastCallKeywords(func, stack, ...
}
if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallKeywords(func, stack,...
}
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
if (kwdict == NULL) {
return NULL;
}
}
else {
kwdict = NULL;
}
result = _PyObject_FastCallDict(func, stack, nargs, k...
Py_XDECREF(kwdict);
return result;
}
}}
関数オブジェクトでなく、Cで実装された関数でもないので_PyO...
*PyType_Ready再び [#gd4a7722]
さてというわけで_PyObject_FastCallDictが呼び出されてその...
まずは前提として、親クラスは指定していないので以下のif文...
#code(C){{
/* Initialize tp_base (defaults to BaseObject unless ...
base = type->tp_base;
if (base == NULL && type != &PyBaseObject_Type) {
base = type->tp_base = &PyBaseObject_Type;
Py_INCREF(base);
}
}}
その後読み進めていくと以下の部分があります。
#code(C){{
/* Initialize tp_dict properly */
bases = type->tp_mro;
n = PyTuple_GET_SIZE(bases);
for (i = 1; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
if (PyType_Check(b))
inherit_slots(type, (PyTypeObject *)b);
}
}}
inherit_slotsへ。
#code(C){{
static void
inherit_slots(PyTypeObject *type, PyTypeObject *base)
{
PyTypeObject *basebase;
#undef SLOTDEFINED
#undef COPYSLOT
#undef COPYNUM
#undef COPYSEQ
#undef COPYMAP
#undef COPYBUF
#define SLOTDEFINED(SLOT) \
(base->SLOT != 0 && \
(basebase == NULL || base->SLOT != basebase->SLOT))
#define COPYSLOT(SLOT) \
if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = ba...
// 省略
basebase = base->tp_base;
COPYSLOT(tp_dealloc);
if (type->tp_getattr == NULL && type->tp_getattro == ...
type->tp_getattr = base->tp_getattr;
type->tp_getattro = base->tp_getattro;
}
if (type->tp_setattr == NULL && type->tp_setattro == ...
type->tp_setattr = base->tp_setattr;
type->tp_setattro = base->tp_setattro;
}
/* tp_reserved is ignored */
COPYSLOT(tp_repr);
/* tp_hash see tp_richcompare */
COPYSLOT(tp_call);
// 省略
}
}}
というわけで、新しく作ったクラスのtp_callはBaseObjectのtp...
と見に行ったらBaseObjectのtp_callもNULLでした。BaseObject...
*fixup_slot_dispatchers (Objects/typeobject.c) [#b4e915d8]
type_callは前回も見ました。大雑把に言うと、
+tp_newを呼び出してオブジェクトを作って
+tp_initで初期化
を行います。ここで、今回はそれぞれobject_new、object_init...
・・・と思ったのですが、object_init見ても__init__メソッド...
前回は省略してましたが、type_newの中でPyType_Readyの後でf...
#code(C){{
/* Initialize the rest */
if (PyType_Ready(type) < 0)
goto error;
/* Put the proper slots in place */
fixup_slot_dispatchers(type);
}}
#code(C){{
/* Store the proper functions in the slot dispatches at c...
definition time, based upon which operations the class...
dict. */
static void
fixup_slot_dispatchers(PyTypeObject *type)
{
slotdef *p;
init_slotdefs();
for (p = slotdefs; p->name; )
p = update_one_slot(type, p);
}
}}
slotdefsはこんな感じです。
#code(C){{
typedef struct wrapperbase slotdef;
#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
{NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTIO...
PyDoc_STR(DOC), FLAGS}
static slotdef slotdefs[] = {
// 省略
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfun...
"__call__($self, /, *args, **kwargs)\n--\n\nCa...
PyWrapperFlag_KEYWORDS),
// 省略
{NULL}
};
}}
update_one_slotはちょっとややこしい。要約すると、「Python...
#code(C){{
static slotdef *
update_one_slot(PyTypeObject *type, slotdef *p)
{
PyObject *descr;
PyWrapperDescrObject *d;
void *generic = NULL, *specific = NULL;
int use_generic = 0;
int offset = p->offset;
void **ptr = slotptr(type, offset);
if (ptr == NULL) {
do {
++p;
} while (p->offset == offset);
return p;
}
do {
descr = _PyType_Lookup(type, p->name_strobj);
if (descr == NULL) {
if (ptr == (void**)&type->tp_iternext) {
specific = (void *)_PyObject_NextNotImple...
}
continue;
}
if (Py_TYPE(descr) == &PyWrapperDescr_Type &&
((PyWrapperDescrObject *)descr)->d_base->name...
// 省略
}
else if (Py_TYPE(descr) == &PyCFunction_Type &&
PyCFunction_GET_FUNCTION(descr) ==
(PyCFunction)tp_new_wrapper &&
ptr == (void**)&type->tp_new)
{
// 省略
}
else if (descr == Py_None &&
ptr == (void**)&type->tp_hash) {
// 省略
}
else {
use_generic = 1;
generic = p->function;
}
} while ((++p)->offset == offset);
if (specific && !use_generic)
*ptr = specific;
else
*ptr = generic;
return p;
}
}}
*slot_tp_init (Objects/typeobject.c) [#c37bb761]
というわけでslot_tp_initです。
#code(C){{
static int
slot_tp_init(PyObject *self, PyObject *args, PyObject *kw...
{
_Py_IDENTIFIER(__init__);
PyObject *meth = lookup_method(self, &PyId___init__);
PyObject *res;
if (meth == NULL)
return -1;
res = PyObject_Call(meth, args, kwds);
Py_DECREF(meth);
if (res == NULL)
return -1;
if (res != Py_None) {
PyErr_Format(PyExc_TypeError,
"__init__() should return None, not ...
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return -1;
}
Py_DECREF(res);
return 0;
}
}}
lookup_method、初めはよくわからなかったのですがどうにもse...
#code(C){{
static PyObject *
lookup_method(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res = lookup_maybe(self, attrid);
if (res == NULL && !PyErr_Occurred())
PyErr_SetObject(PyExc_AttributeError, attrid->obj...
return res;
}
static PyObject *
lookup_maybe(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res;
res = _PyType_LookupId(Py_TYPE(self), attrid);
if (res != NULL) {
descrgetfunc f;
if ((f = Py_TYPE(res)->tp_descr_get) == NULL)
Py_INCREF(res);
else
res = f(res, self, (PyObject *)(Py_TYPE(self)...
}
return res;
}
}}
resはFunctionObjectです。そのtp_descr_getはfunc_descr_get...
**func_descr_get (Objects/funcobject.c) [#reb6abcf]
#code(C){{
/* Bind a function to an object */
static PyObject *
func_descr_get(PyObject *func, PyObject *obj, PyObject *t...
{
if (obj == Py_None || obj == NULL) {
Py_INCREF(func);
return func;
}
return PyMethod_New(func, obj);
}
}}
PyMethod_NewはObjects/classobject.cに書かれています。やや...
#code(C){{
PyObject *
PyMethod_New(PyObject *func, PyObject *self)
{
PyMethodObject *im;
if (self == NULL) {
PyErr_BadInternalCall();
return NULL;
}
im = free_list;
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
(void)PyObject_INIT(im, &PyMethod_Type);
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Ty...
if (im == NULL)
return NULL;
}
im->im_weakreflist = NULL;
Py_INCREF(func);
im->im_func = func;
Py_XINCREF(self);
im->im_self = self;
_PyObject_GC_TRACK(im);
return (PyObject *)im;
}
}}
self設定されていますね。というわけで、lookup_methodにより...
*method_call (Objects/classobject.c) [#lcd11bd8]
method_call
#code(C){{
static PyObject *
method_call(PyObject *method, PyObject *args, PyObject *k...
{
PyObject *self, *func;
self = PyMethod_GET_SELF(method);
func = PyMethod_GET_FUNCTION(method);
return _PyObject_Call_Prepend(func, self, args, kwarg...
}
}}
_PyObject_Call_PrependはObjects/abstract.cに書かれていて...
_PyObject_FastCallDictは同じくabstract.cに書かれていて、...
_PyFunction_FastCallDictはceval.cです。今の場合は_PyFunct...
*STORE_ATTR [#l8570877]
最後に属性を設定しているところを確認しましょう。すなわち...
#code(Python){{
self.x = x
}}
対応するバイトコードは、
4 0 LOAD_FAST 1 (x)
2 LOAD_FAST 0 (self)
4 STORE_ATTR 0 (x)
で、STORE_ATTRの処理部分
#code(C){{
TARGET(STORE_ATTR) {
PyObject *name = GETITEM(names, oparg);
PyObject *owner = TOP();
PyObject *v = SECOND();
int err;
STACKADJ(-2);
err = PyObject_SetAttr(owner, name, v);
Py_DECREF(v);
Py_DECREF(owner);
if (err != 0)
goto error;
DISPATCH();
}
}}
Objects/object.cに移動。
#code(C){{
int
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *v...
{
PyTypeObject *tp = Py_TYPE(v);
int err;
Py_INCREF(name);
PyUnicode_InternInPlace(&name);
if (tp->tp_setattro != NULL) {
err = (*tp->tp_setattro)(v, name, value);
Py_DECREF(name);
return err;
}
// 省略
}
}}
tp_setattroはPyObject_GenericSetAttrに設定されています。
#code(C){{
int
PyObject_GenericSetAttr(PyObject *obj, PyObject *name, Py...
{
return _PyObject_GenericSetAttrWithDict(obj, name, va...
}
int
_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject ...
PyObject *value, PyObjec...
{
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr;
descrsetfunc f;
PyObject **dictptr;
int res = -1;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not ...
name->ob_type->tp_name);
return -1;
}
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0)
return -1;
Py_INCREF(name);
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
// 省略
}
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
res = _PyObjectDict_SetItem(tp, dictptr, name, va...
}
else {
// 省略
}
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetObject(PyExc_AttributeError, name);
done:
Py_XDECREF(descr);
Py_DECREF(name);
return res;
}
}}
_PyObject_GetDictPtrはdictoffsetで指定された位置を返しま...
なおこの時点ではまだオブジェクトに属性辞書は紐づいていま...
*おわりに [#eccb50f9]
今回はインスタンスの作成について見てきました。
-メソッドの継承
-継承と言いつつ子クラスでオーバーライドされているものがあ...
-さらにCレベルでのオーバーライドとPythonレベルでのオーバ...
-いつの間にselfがバインドされたんだ?の場所探し
-インスタンス辞書も一筋縄ではいかない
となかなか盛沢山でしたね。特にインスタンス辞書は素直にPyO...
終了行:
[[Pythonを読む]]
#contents
*はじめに [#g26b6764]
PyObjectから入ったので長くなりましたがようやくクラスが作...
#code(Python){{
foo = Foo(123)
}}
対応するバイトコードこんな感じ。
9 14 LOAD_NAME 0 (Foo)
16 LOAD_CONST 2 (123)
18 CALL_FUNCTION 1
20 STORE_NAME 1 (foo)
*call_function (Python/ceval.c) [#e34fe680]
というわけでCALL_FUNCTIONに対応するcall_functionです。前...
#code(C){{
static PyObject *
call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyO...
{
PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_...
Py_ssize_t nargs = oparg - nkwargs;
PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
if (PyCFunction_Check(func)) {
// こっちじゃない
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(fun...
/* optimize access to bound methods */
PyObject *self = PyMethod_GET_SELF(func);
PCALL(PCALL_METHOD);
PCALL(PCALL_BOUND_METHOD);
Py_INCREF(self);
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
nargs++;
}
else {
Py_INCREF(func);
}
stack = (*pp_stack) - nargs - nkwargs;
if (PyFunction_Check(func)) {
x = fast_function(func, stack, nargs, kwnames);
}
else {
x = _PyObject_FastCallKeywords(func, stack, n...
}
Py_DECREF(func);
}
// 省略
return x;
}
}}
メソッド呼び出し用の加工処理っぽいことしてますがそれはま...
#code(C){{
PyObject *
_PyObject_FastCallKeywords(PyObject *func, PyObject **sta...
PyObject *kwnames)
{
PyObject *kwdict, *result;
Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_...
if (PyFunction_Check(func)) {
return _PyFunction_FastCallKeywords(func, stack, ...
}
if (PyCFunction_Check(func)) {
return _PyCFunction_FastCallKeywords(func, stack,...
}
if (nkwargs > 0) {
kwdict = _PyStack_AsDict(stack + nargs, kwnames);
if (kwdict == NULL) {
return NULL;
}
}
else {
kwdict = NULL;
}
result = _PyObject_FastCallDict(func, stack, nargs, k...
Py_XDECREF(kwdict);
return result;
}
}}
関数オブジェクトでなく、Cで実装された関数でもないので_PyO...
*PyType_Ready再び [#gd4a7722]
さてというわけで_PyObject_FastCallDictが呼び出されてその...
まずは前提として、親クラスは指定していないので以下のif文...
#code(C){{
/* Initialize tp_base (defaults to BaseObject unless ...
base = type->tp_base;
if (base == NULL && type != &PyBaseObject_Type) {
base = type->tp_base = &PyBaseObject_Type;
Py_INCREF(base);
}
}}
その後読み進めていくと以下の部分があります。
#code(C){{
/* Initialize tp_dict properly */
bases = type->tp_mro;
n = PyTuple_GET_SIZE(bases);
for (i = 1; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
if (PyType_Check(b))
inherit_slots(type, (PyTypeObject *)b);
}
}}
inherit_slotsへ。
#code(C){{
static void
inherit_slots(PyTypeObject *type, PyTypeObject *base)
{
PyTypeObject *basebase;
#undef SLOTDEFINED
#undef COPYSLOT
#undef COPYNUM
#undef COPYSEQ
#undef COPYMAP
#undef COPYBUF
#define SLOTDEFINED(SLOT) \
(base->SLOT != 0 && \
(basebase == NULL || base->SLOT != basebase->SLOT))
#define COPYSLOT(SLOT) \
if (!type->SLOT && SLOTDEFINED(SLOT)) type->SLOT = ba...
// 省略
basebase = base->tp_base;
COPYSLOT(tp_dealloc);
if (type->tp_getattr == NULL && type->tp_getattro == ...
type->tp_getattr = base->tp_getattr;
type->tp_getattro = base->tp_getattro;
}
if (type->tp_setattr == NULL && type->tp_setattro == ...
type->tp_setattr = base->tp_setattr;
type->tp_setattro = base->tp_setattro;
}
/* tp_reserved is ignored */
COPYSLOT(tp_repr);
/* tp_hash see tp_richcompare */
COPYSLOT(tp_call);
// 省略
}
}}
というわけで、新しく作ったクラスのtp_callはBaseObjectのtp...
と見に行ったらBaseObjectのtp_callもNULLでした。BaseObject...
*fixup_slot_dispatchers (Objects/typeobject.c) [#b4e915d8]
type_callは前回も見ました。大雑把に言うと、
+tp_newを呼び出してオブジェクトを作って
+tp_initで初期化
を行います。ここで、今回はそれぞれobject_new、object_init...
・・・と思ったのですが、object_init見ても__init__メソッド...
前回は省略してましたが、type_newの中でPyType_Readyの後でf...
#code(C){{
/* Initialize the rest */
if (PyType_Ready(type) < 0)
goto error;
/* Put the proper slots in place */
fixup_slot_dispatchers(type);
}}
#code(C){{
/* Store the proper functions in the slot dispatches at c...
definition time, based upon which operations the class...
dict. */
static void
fixup_slot_dispatchers(PyTypeObject *type)
{
slotdef *p;
init_slotdefs();
for (p = slotdefs; p->name; )
p = update_one_slot(type, p);
}
}}
slotdefsはこんな感じです。
#code(C){{
typedef struct wrapperbase slotdef;
#define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \
{NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTIO...
PyDoc_STR(DOC), FLAGS}
static slotdef slotdefs[] = {
// 省略
FLSLOT("__call__", tp_call, slot_tp_call, (wrapperfun...
"__call__($self, /, *args, **kwargs)\n--\n\nCa...
PyWrapperFlag_KEYWORDS),
// 省略
{NULL}
};
}}
update_one_slotはちょっとややこしい。要約すると、「Python...
#code(C){{
static slotdef *
update_one_slot(PyTypeObject *type, slotdef *p)
{
PyObject *descr;
PyWrapperDescrObject *d;
void *generic = NULL, *specific = NULL;
int use_generic = 0;
int offset = p->offset;
void **ptr = slotptr(type, offset);
if (ptr == NULL) {
do {
++p;
} while (p->offset == offset);
return p;
}
do {
descr = _PyType_Lookup(type, p->name_strobj);
if (descr == NULL) {
if (ptr == (void**)&type->tp_iternext) {
specific = (void *)_PyObject_NextNotImple...
}
continue;
}
if (Py_TYPE(descr) == &PyWrapperDescr_Type &&
((PyWrapperDescrObject *)descr)->d_base->name...
// 省略
}
else if (Py_TYPE(descr) == &PyCFunction_Type &&
PyCFunction_GET_FUNCTION(descr) ==
(PyCFunction)tp_new_wrapper &&
ptr == (void**)&type->tp_new)
{
// 省略
}
else if (descr == Py_None &&
ptr == (void**)&type->tp_hash) {
// 省略
}
else {
use_generic = 1;
generic = p->function;
}
} while ((++p)->offset == offset);
if (specific && !use_generic)
*ptr = specific;
else
*ptr = generic;
return p;
}
}}
*slot_tp_init (Objects/typeobject.c) [#c37bb761]
というわけでslot_tp_initです。
#code(C){{
static int
slot_tp_init(PyObject *self, PyObject *args, PyObject *kw...
{
_Py_IDENTIFIER(__init__);
PyObject *meth = lookup_method(self, &PyId___init__);
PyObject *res;
if (meth == NULL)
return -1;
res = PyObject_Call(meth, args, kwds);
Py_DECREF(meth);
if (res == NULL)
return -1;
if (res != Py_None) {
PyErr_Format(PyExc_TypeError,
"__init__() should return None, not ...
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return -1;
}
Py_DECREF(res);
return 0;
}
}}
lookup_method、初めはよくわからなかったのですがどうにもse...
#code(C){{
static PyObject *
lookup_method(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res = lookup_maybe(self, attrid);
if (res == NULL && !PyErr_Occurred())
PyErr_SetObject(PyExc_AttributeError, attrid->obj...
return res;
}
static PyObject *
lookup_maybe(PyObject *self, _Py_Identifier *attrid)
{
PyObject *res;
res = _PyType_LookupId(Py_TYPE(self), attrid);
if (res != NULL) {
descrgetfunc f;
if ((f = Py_TYPE(res)->tp_descr_get) == NULL)
Py_INCREF(res);
else
res = f(res, self, (PyObject *)(Py_TYPE(self)...
}
return res;
}
}}
resはFunctionObjectです。そのtp_descr_getはfunc_descr_get...
**func_descr_get (Objects/funcobject.c) [#reb6abcf]
#code(C){{
/* Bind a function to an object */
static PyObject *
func_descr_get(PyObject *func, PyObject *obj, PyObject *t...
{
if (obj == Py_None || obj == NULL) {
Py_INCREF(func);
return func;
}
return PyMethod_New(func, obj);
}
}}
PyMethod_NewはObjects/classobject.cに書かれています。やや...
#code(C){{
PyObject *
PyMethod_New(PyObject *func, PyObject *self)
{
PyMethodObject *im;
if (self == NULL) {
PyErr_BadInternalCall();
return NULL;
}
im = free_list;
if (im != NULL) {
free_list = (PyMethodObject *)(im->im_self);
(void)PyObject_INIT(im, &PyMethod_Type);
numfree--;
}
else {
im = PyObject_GC_New(PyMethodObject, &PyMethod_Ty...
if (im == NULL)
return NULL;
}
im->im_weakreflist = NULL;
Py_INCREF(func);
im->im_func = func;
Py_XINCREF(self);
im->im_self = self;
_PyObject_GC_TRACK(im);
return (PyObject *)im;
}
}}
self設定されていますね。というわけで、lookup_methodにより...
*method_call (Objects/classobject.c) [#lcd11bd8]
method_call
#code(C){{
static PyObject *
method_call(PyObject *method, PyObject *args, PyObject *k...
{
PyObject *self, *func;
self = PyMethod_GET_SELF(method);
func = PyMethod_GET_FUNCTION(method);
return _PyObject_Call_Prepend(func, self, args, kwarg...
}
}}
_PyObject_Call_PrependはObjects/abstract.cに書かれていて...
_PyObject_FastCallDictは同じくabstract.cに書かれていて、...
_PyFunction_FastCallDictはceval.cです。今の場合は_PyFunct...
*STORE_ATTR [#l8570877]
最後に属性を設定しているところを確認しましょう。すなわち...
#code(Python){{
self.x = x
}}
対応するバイトコードは、
4 0 LOAD_FAST 1 (x)
2 LOAD_FAST 0 (self)
4 STORE_ATTR 0 (x)
で、STORE_ATTRの処理部分
#code(C){{
TARGET(STORE_ATTR) {
PyObject *name = GETITEM(names, oparg);
PyObject *owner = TOP();
PyObject *v = SECOND();
int err;
STACKADJ(-2);
err = PyObject_SetAttr(owner, name, v);
Py_DECREF(v);
Py_DECREF(owner);
if (err != 0)
goto error;
DISPATCH();
}
}}
Objects/object.cに移動。
#code(C){{
int
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *v...
{
PyTypeObject *tp = Py_TYPE(v);
int err;
Py_INCREF(name);
PyUnicode_InternInPlace(&name);
if (tp->tp_setattro != NULL) {
err = (*tp->tp_setattro)(v, name, value);
Py_DECREF(name);
return err;
}
// 省略
}
}}
tp_setattroはPyObject_GenericSetAttrに設定されています。
#code(C){{
int
PyObject_GenericSetAttr(PyObject *obj, PyObject *name, Py...
{
return _PyObject_GenericSetAttrWithDict(obj, name, va...
}
int
_PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject ...
PyObject *value, PyObjec...
{
PyTypeObject *tp = Py_TYPE(obj);
PyObject *descr;
descrsetfunc f;
PyObject **dictptr;
int res = -1;
if (!PyUnicode_Check(name)){
PyErr_Format(PyExc_TypeError,
"attribute name must be string, not ...
name->ob_type->tp_name);
return -1;
}
if (tp->tp_dict == NULL && PyType_Ready(tp) < 0)
return -1;
Py_INCREF(name);
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
// 省略
}
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
res = _PyObjectDict_SetItem(tp, dictptr, name, va...
}
else {
// 省略
}
if (res < 0 && PyErr_ExceptionMatches(PyExc_KeyError))
PyErr_SetObject(PyExc_AttributeError, name);
done:
Py_XDECREF(descr);
Py_DECREF(name);
return res;
}
}}
_PyObject_GetDictPtrはdictoffsetで指定された位置を返しま...
なおこの時点ではまだオブジェクトに属性辞書は紐づいていま...
*おわりに [#eccb50f9]
今回はインスタンスの作成について見てきました。
-メソッドの継承
-継承と言いつつ子クラスでオーバーライドされているものがあ...
-さらにCレベルでのオーバーライドとPythonレベルでのオーバ...
-いつの間にselfがバインドされたんだ?の場所探し
-インスタンス辞書も一筋縄ではいかない
となかなか盛沢山でしたね。特にインスタンス辞書は素直にPyO...
ページ名: