Python源码解析——Class实例创建

本文只分析Python类实例的创建,不涉及类本身的构建(类本身的构建将会在接下来的文章中介绍)。

# example
class A(object):
    pass
obj_a = A()

上面这一段代码对应的opcode如下:

 0 LOAD_CONST               1 ('A')
 3 LOAD_GLOBAL              0 (object)
 6 BUILD_TUPLE              1
 9 LOAD_CONST               2 (<code object A at 0x104f367b0, file "<stdin>", line 2>)
12 MAKE_FUNCTION            0
15 CALL_FUNCTION            0
18 BUILD_CLASS
19 STORE_FAST               0 (A)

22 LOAD_FAST                0 (A)
25 CALL_FUNCTION            0
28 STORE_FAST               1 (obj_a)

说明几个关键的opcode,BUILD_CLASS用于创建一个名为A的Class,在LOAD_FAST的时候Python虚拟机加载A,然后执行CALL_FUNCTION

1.从CALL_FUNCTION机器码看起

下面是从CALL_FUNCTION开始的函数调用流程:

CALL_FUNCTION->call_function->do_call->PyObject_Call...

PyObject_Call从函数命名很容易理解,这个函数是对PyObject进行调用。

PyObject *
PyObject_Call(PyObject *func, PyObject *arg, PyObject *kw) {
    if ((call = func->ob_type->tp_call) != NULL) {
        ...
        result = (*call)(func, arg, kw);
        ...
    }
    ...

func在这里对应的就是类A,当然我们在创建obj_a的时候是没有参数的,因此arg和kw便没有任何东西。在if语句中获取func->ob_type->tp_call,func就是A,那么ob_type在这里是PyType_Type。

# in typeobject.c
PyTypeObject PyType_Type = {
    ....
    (ternaryfunc)type_call,                     /* tp_call */
    ....

就是上面这个实例,其对应的tp_call是type_call这个函数。

static PyObject *
type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) {
    ....
    obj = type->tp_new(type, args, kwds);
    ....

type->tp_new中的type还是类A,tp_new则是其基类object的tpnew(原因很简单,我们在A的定义中并没有重载\_new__函数),object的真面目就是PyBaseObject_Type。

# in typeobject.c
PyTypeObject PyBaseObject_Type = { 
    ....
    object_new,                                 /* tp_new */
    ....

2.object_new都做了什么

static PyObject *
object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
    ....
    return type->tp_alloc(type, 0);
}

object_new做的事情很简单,就是调用类A的tp_alloc,这里的tp_alloc的实现是PyType_GenericAlloc函数,我们在前文也提到过。

3.总结

到这里obj_a的创建流程基本走完,无非后面会调用tpnew(如果我们定义了\_init__就会调用我们的这个方法),但obj_a在内存中的形式已经确定,就是一个简单的PyObject。

typedef struct _object {
    PyObject_HEAD
} PyObject;

其ob_type对应的就是类A