- 大师兄的Python源码学习笔记(二十七): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十五): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十三): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十八): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十六): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十四): 虚拟机中的类机制(
- 大师兄的Python源码学习笔记(二十九): 运行环境初始化(一
- 大师兄的Python源码学习笔记(二十一): 虚拟机中的函数机制
- 大师兄的Python源码学习笔记(二十): 虚拟机中的函数机制(
- 大师兄的Python源码学习笔记(二十二): 虚拟机中的类机制(
大师兄的Python源码学习笔记(二十五): 虚拟机中的类机制(四)
大师兄的Python源码学习笔记(二十七): 虚拟机中的类机制(六)
三. 用户自定义Class
2. 从class对象到instance对象
- 在虚拟机执行时,在内存中运行的是一个个instance对象而不是class对象。
demo.py
a = A()
13 16 LOAD_NAME 1 (A)
18 CALL_FUNCTION 0
20 STORE_NAME 2 (a)
- 从这段字节码可以看出,虚拟机通过执行CALL_FUNCTION,调用class对象A,创建了instance对象a。
Python\ceval.c
TARGET(CALL_FUNCTION_EX) {
PyObject *func, *callargs, *kwargs = NULL, *result;
... ...
result = do_call_core(func, callargs, kwargs);
... ...
}
Python\ceval.c
static PyObject *
do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
{
if (PyCFunction_Check(func)) {
PyObject *result;
PyThreadState *tstate = PyThreadState_GET();
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
return result;
}
else {
return PyObject_Call(func, callargs, kwdict);
}
}
Python\ceval.c
PyObject *
PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs)
{
ternaryfunc call;
PyObject *result;
/* PyObject_Call() must not be called with an exception set,
because it can clear it (directly or indirectly) and so the
caller loses its exception */
assert(!PyErr_Occurred());
assert(PyTuple_Check(args));
assert(kwargs == NULL || PyDict_Check(kwargs));
if (PyFunction_Check(callable)) {
return _PyFunction_FastCallDict(callable,
&PyTuple_GET_ITEM(args, 0),
PyTuple_GET_SIZE(args),
kwargs);
}
else if (PyCFunction_Check(callable)) {
return PyCFunction_Call(callable, args, kwargs);
}
else {
call = callable->ob_type->tp_call;
if (call == NULL) {
PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
callable->ob_type->tp_name);
return NULL;
}
if (Py_EnterRecursiveCall(" while calling a Python object"))
return NULL;
result = (*call)(callable, args, kwargs);
Py_LeaveRecursiveCall();
return _Py_CheckFunctionResult(callable, result, NULL);
}
}
- 虚拟机一路从CALL_FUNCTION_EX开始,经过PyObject_Call,最终进入PyObject_Call。
- 到这里,虚拟机会寻找class对象<class A>的type中定义的tp_call操作。
Objects\typeobject.c
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
... ...
obj = type->tp_new(type, args, kwds);
... ...
return obj;
}
- 执行对象的tp_call时,将调用对象的tp_new创建instance对象。
- 在创建class对象<class A>时,虚拟机调用了PyType_Ready对<class A>进行初始化,其中继承了基类的操作。
- 所以A.tp_new实际上也是object.tp_new。
Objects\typeobject.c
PyTypeObject PyBaseObject_Type = {
... ...
object_new, /* tp_new */
... ...
};
- 而PyBaseObject_Type对应的tp_new方法为object_new。
- 所以创建class对象和创建instnace对象的不同之处是在于tp_new不同,创建class对象时,虚拟机使用的是type_new,而对于instance对象则使用object_new。
Objects\typeobject.c
static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
... ...
return type->tp_alloc(type, 0);
}
- 在object_new中调用了tp_alloc,也是继承自object,调用了PyType_GenericAlloc。
Objects\typeobject.c
PyTypeObject PyBaseObject_Type = {
... ...
PyType_GenericAlloc, /* tp_alloc */
... ...
};
- 而PyType_GenericAlloc将申请24字节的内存空间。
A.tp_basicsize = PyBaseObject_Type.tp_basicsize + 8 = sizeof(PyObject) + 8 = 24
A.tp_itemsize = PyBaseObject_Type.tp_itemsize = 0
Objects\typeobject.c
PyObject *
PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)
{
PyObject *obj;
const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
/* note that we need to add one, for the sentinel */
if (PyType_IS_GC(type))
obj = _PyObject_GC_Malloc(size);
else
obj = (PyObject *)PyObject_MALLOC(size);
if (obj == NULL)
return PyErr_NoMemory();
memset(obj, '\0', size);
if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
Py_INCREF(type);
if (type->tp_itemsize == 0)
(void)PyObject_INIT(obj, type);
else
(void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
if (PyType_IS_GC(type))
_PyObject_GC_TRACK(obj);
return obj;
}
- 所以object_new实际只是申请了24个字节的内存空间。
- 申请空间后回到tp_call,会尝试进行初始化:
Objects\typeobject.c
static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *obj;
... ...
obj = type->tp_new(type, args, kwds);
... ...
type = Py_TYPE(obj);
if (type->tp_init != NULL) {
int res = type->tp_init(obj, args, kwds);
if (res < 0) {
assert(PyErr_Occurred());
Py_DECREF(obj);
obj = NULL;
}
else {
assert(!PyErr_Occurred());
}
}
return obj;
}
Include\object.h
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
- 这里tp_init在PyType_Ready时会继承PyBaseObject_Type的object_init操作。
Objects\typeobject.c
PyTypeObject PyBaseObject_Type = {
... ...
object_init, /* tp_init */
... ...
};
- 但由于A中重写了
__init__
,所以在fixup_slot_dispatchers中,tp_init会指向slotdefs中指定的与__init__对应的slot_tp_init。
demo.py
class A(object):
name = 'A'
def ___init__(self):
print('A::__init__')
... ...
Objects\typeobject.c
static int
slot_tp_init(PyObject *self, PyObject *args, PyObject *kwds)
{
_Py_IDENTIFIER(__init__);
int unbound;
PyObject *meth = lookup_method(self, &PyId___init__, &unbound);
PyObject *res;
if (meth == NULL)
return -1;
if (unbound) {
res = _PyObject_Call_Prepend(meth, self, args, kwds);
}
else {
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 '%.200s'",
Py_TYPE(res)->tp_name);
Py_DECREF(res);
return -1;
}
Py_DECREF(res);
return 0;
}
- 在这段代码中,虚拟机首先通过lookup_method在class对象及其mro列表中所搜属性__init__对应的操作,然后通过PyObject_Call调用该操作。
- 如果没有重写__init__,那么最终结果将调用object_init。
Objects\typeobject.c
static int
object_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyTypeObject *type = Py_TYPE(self);
if (excess_args(args, kwds)) {
if (type->tp_init != object_init) {
PyErr_SetString(PyExc_TypeError, "object.__init__() takes no arguments");
return -1;
}
if (type->tp_new == object_new) {
PyErr_Format(PyExc_TypeError, "%.200s().__init__() takes no arguments",
type->tp_name);
return -1;
}
}
return 0;
}
- 在object_init中,虚拟机几乎什么也没做,直接返回0。
- 所以当创建instance对象时,实际上是没有进行任何初始化动作的。
- class对象创建instance对象的源码部分与Python一致,需要经过两个魔法函数:
class.__new__(class, args, kwds)
class.__init__(instance, args, kwds)
网友评论