Py学习  »  Python

Python源码分析:类的机制

Python中文社区 • 5 年前 • 778 次点击  

--  Illustrations by Daniel Liang --

作者:小屋子大侠,目前主要从事于python后端相关工作,使用使用python大概2年半的时间,平常喜欢分析工作中使用的工具的源码,如supervisor,gunicorn,django等,并编写了相应的源码分析博客,除了使用工具的分析外,对python的底层实现也有相应兴趣并编写过python源码有关的博客,目前主要学习于操作系统相关内容。个人博客地址https://blog.csdn.net/qq_33339479/


本文主要分析Python中类时如何实现的,在Python中,一切都是对象;任何对象都有一个type,都可以通过class属性,一般情况下为type对应于Python源码中的PyTypeType;在Python的类中,都直接或者间接与Object有关联,都是Object的子类,对应Python中PyBaseObjectType。在Python的启动执行流程一文中有介绍,在Python启动的过程中会首先对默认的类型进行初始化,我们就从这里开始分析。

分析 初始化代码如下:

  1. void

  2. _Py_ReadyTypes(void)

  3. {

  4.    if (PyType_Ready(&PyType_Type ) < 0)

  5.        Py_FatalError("Can't initialize 'type'");

  6.    if (PyType_Ready(&_PyWeakref_RefType) < 0)

  7.        Py_FatalError("Can't initialize 'weakref'");

  8.    if (PyType_Ready(&PyBool_Type) < 0 )

  9.        Py_FatalError("Can't initialize 'bool'");

  10.    if (PyType_Ready(&PyString_Type) < 0)

  11.        Py_FatalError("Can't initialize 'str'");

  12.    if (PyType_Ready(&PyList_Type) < 0)

  13.        Py_FatalError ("Can't initialize 'list'");

  14.    if (PyType_Ready(&PyNone_Type) < 0)

  15.        Py_FatalError("Can't initialize type(None)");

  16.    if (PyType_Ready(&PyNotImplemented_Type) < 0)

  17.        Py_FatalError("Can't initialize type(NotImplemented)");

  18. }

这里分析下PyTypeReady(&PyTypeType)初始化过程,首先我们查看下PyType_Type类型的结构:

  1. PyTypeObject PyType_Type = {

  2.    PyObject_HEAD_INIT(&PyType_Type)      //  类型还是PyType_Type

  3.    0,                  /* ob_size */

  4.    "type",                 /* tp_name */

  5.    sizeof(PyHeapTypeObject),       /* tp_basicsize */

  6.    sizeof(PyMemberDef),            /* tp_itemsize */

  7.    (destructor)type_dealloc,       /* tp_dealloc */

  8.    0,                  /* tp_print */

  9.    0,                  /* tp_getattr */

  10.    0,                  /* tp_setattr */

  11.    type_compare,               /* tp_compare */

  12.    (reprfunc)type_repr,            /* tp_repr */

  13.     0,                  /* tp_as_number */

  14.    0,                  /* tp_as_sequence */

  15.    0,                  /* tp_as_mapping */

  16.    (hashfunc)_Py_HashPointer,      /* tp_hash */    // 哈希函数

  17.    (ternaryfunc)type_call,         /* tp_call */    // tp_call函数

  18.    0,                  /* tp_str */

  19.    ( getattrofunc)type_getattro,        /* tp_getattro */

  20.    (setattrofunc)type_setattro,        /* tp_setattro */

  21.    0,                  /* tp_as_buffer */

  22.    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |

  23.        Py_TPFLAGS_BASETYPE,        /* tp_flags */

  24.    type_doc,               /* tp_doc */

  25.    (traverseproc)type_traverse ,        /* tp_traverse */

  26.    (inquiry)type_clear,            /* tp_clear */

  27.    0,                  /* tp_richcompare */

  28.    offsetof(PyTypeObject, tp_weaklist),    /* tp_weaklistoffset */

  29.    0,                  /* tp_iter */

  30.    0,                  /* tp_iternext */

  31.    type_methods,               /* tp_methods */

  32.    type_members,               /* tp_members */

  33.    type_getsets,               /* tp_getset */

  34.    0,                  /* tp_base */

  35.    0,                  /* tp_dict */

  36.    0,                  /* tp_descr_get */

  37.    0,                  /* tp_descr_set */

  38.    offsetof(PyTypeObject, tp_dict),    /* tp_dictoffset */

  39.    0 ,                  /* tp_init */

  40.    0,                  /* tp_alloc */

  41.    type_new,               /* tp_new */

  42.    PyObject_GC_Del,                /* tp_free */

  43.    (inquiry)type_is_gc,            /* tp_is_gc */

  44. };

由此可见type定义中的tp_base为空,在初始化过程中就会将基类换成Object;我们看完定义后再查看初始化过程:

  1. int

  2. PyType_Ready(PyTypeObject *type)

  3. {

  4.    PyObject *dict, *bases;

  5.    PyTypeObject *base;

  6.    Py_ssize_t i, n;

  7.    if (type->tp_flags & Py_TPFLAGS_READY) {

  8.        assert( type->tp_dict != NULL);

  9.        return 0;

  10.    }

  11.    assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);

  12.    type->tp_flags |= Py_TPFLAGS_READYING;

  13. #ifdef Py_TRACE_REFS

  14.    /* PyType_Ready is the closest thing we have to a choke point

  15.     * for type objects, so is the best place I can think of to try

  16.     * to get type objects into the doubly-linked list of all objects.

  17.     * Still, not all type objects go thru PyType_Ready.

  18.     */

  19.    _Py_AddToAllObjects((PyObject *)type, 0);

  20. #endif

  21.    /* Initialize tp_base (defaults to BaseObject unless that's us) */

  22.    base = type->tp_base;                                       // 获取初始化类型的基类

  23.    if (base == NULL && type != &PyBaseObject_Type) {           // 如果基类为空,并且初始化的类型不为Object

  24.        base = type->tp_base = &PyBaseObject_Type;              // 将初始化类的基类设置成Object

  25.        Py_INCREF(base);

  26.    }

  27.        /* Now the only way base can still be NULL is if type is

  28.         * &PyBaseObject_Type.

  29.         */

  30.    /* Initialize the base class */

  31.    if (base && base->tp_dict == NULL) {                        // 如果基类的属性列表为空

  32.        if (PyType_Ready(base) < 0)                             // 初始化基类

  33.            goto error;

  34.    }

  35.    /* Initialize ob_type if NULL.  This means extensions that want to be

  36.       compilable separately on Windows can call PyType_Ready() instead of

  37.       initializing the ob_type field of their type objects. */

  38.        /* The test for base != NULL is really unnecessary, since base is only

  39.           NULL when type is &PyBaseObject_Type, and we know its ob_type is

  40.           not NULL (it's initialized to &PyType_Type).  But coverity doesn't

  41.           know that. */

  42.    if (type->ob_type == NULL && base != NULL)                 // 如果初始化类型的类型为空,并且基类不为空

  43.        type->ob_type = base->ob_type;                         // 初始化类型的类型设置成基类的类型

  44.    /* Initialize tp_bases */

  45.    bases = type->tp_bases;                                    // 获取初始化类型的基类列表

  46.    if (bases == NULL) {                                       // 如果基类列表为空

  47.         if (base == NULL)                                      // 如果父类为空

  48.            bases = PyTuple_New(0);                            // 基类则生成一个空的元组

  49.        else

  50.            bases = PyTuple_Pack(1, base);                     // 如果基类不为空,生成长度为1的元组,并将base发入其中

  51.        if (bases == NULL)

  52.            goto error ;

  53.        type->tp_bases = bases;                                // 将生成的bases设置到初始化类型中

  54.    }

  55.    /* Initialize tp_dict */

  56.    dict = type->tp_dict;                                      // 获取类型的属性列表

  57.    if (dict == NULL) {                                        

  58.        dict = PyDict_New();                                   // 如果属性为空,则生成一个字典,并设置到初始化类型中

  59.        if (dict == NULL)

  60.            goto error;

  61.        type->tp_dict = dict;

  62.    }

  63.    /* Add type-specific descriptors to tp_dict */

  64.    if (add_operators(type) < 0)                               // 给该类型添加描述方法

  65.        goto error;

  66.    if (type->tp_methods != NULL) {

  67.        if (add_methods(type, type->tp_methods) < 0)           // 如果类型方法不为空,则将方法包装后添加到初始化类型中

  68.            goto error;

  69.    }

  70.     if (type->tp_members != NULL) {

  71.        if (add_members(type, type->tp_members) < 0)           // 如果类型成员不为空,则将成员包装后添加到初始化类型中

  72.            goto error;

  73.    }

  74.    if (type->tp_getset != NULL) {

  75.        if (add_getset(type, type->tp_getset) < 0)            

  76.            goto error;

  77.    }

  78.    /* Calculate method resolution order */

  79.    if (mro_internal(type) < 0) {                               // 获取初始化类型的基础列表

  80.        goto error;

  81.    }

  82.    /* Inherit special flags from dominant base */

  83.    if (type->tp_base != NULL)

  84.        inherit_special(type, type->tp_base);                  // 如果基类不为空,则继承基类的方法属性等

  85.    /* Initialize tp_dict properly */

  86.    bases = type->tp_mro;                                      // 获取初始化类型的基础列表

  87.    assert(bases != NULL);    

  88.    assert(PyTuple_Check(bases));

  89.    n = PyTuple_GET_SIZE(bases);

  90.    for (i = 1; i < n; i++) {

  91.        PyObject *b = PyTuple_GET_ITEM(bases, i);              // 依次获取基础列表的值

  92.        if (PyType_Check(b))

  93.            inherit_slots(type, (PyTypeObject *)b);            // 继承相应的方法

  94.    }

  95.    /* Sanity check for tp_free. */

  96.     if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&

  97.        (type->tp_free == NULL || type->tp_free == PyObject_Del)) {

  98.            /* This base class needs to call tp_free, but doesn't have

  99.             * one, or its tp_free is for non-gc'ed objects.

  100.             */

  101.        PyErr_Format( PyExc_TypeError, "type '%.100s' participates in "

  102.                 "gc and is a base type but has inappropriate "

  103.                 "tp_free slot",

  104.                 type->tp_name);

  105.        goto error;

  106.    }

  107.    /* if the type dictionary doesn't contain a __doc__, set it from

  108.       the tp_doc slot.

  109.     */

  110.    if (PyDict_GetItemString( type->tp_dict, "__doc__") == NULL) {    // 设置属性的__doc__属性,如果有设置其中,如果没有则设置为空

  111.        if (type->tp_doc != NULL) {

  112.            PyObject *doc = PyString_FromString(type->tp_doc);

  113.            if (doc == NULL)

  114.                goto error;

  115.            PyDict_SetItemString(type->tp_dict, "__doc__", doc);

  116.            Py_DECREF(doc);

  117.        } else {

  118.            PyDict_SetItemString(type->tp_dict,

  119.                         "__doc__", Py_None);

  120.         }

  121.    }

  122.    /* Some more special stuff */

  123.    base = type->tp_base;                                       // 获取基类,如果子类相应的方法为空,则直接将基类方法设置给初始化类型

  124.    if (base != NULL) {

  125.        if (type->tp_as_number == NULL)

  126.            type->tp_as_number = base->tp_as_number;

  127.        if (type->tp_as_sequence == NULL)

  128.            type->tp_as_sequence = base->tp_as_sequence;

  129.        if (type->tp_as_mapping == NULL)

  130.            type->tp_as_mapping = base->tp_as_mapping;

  131.         if (type->tp_as_buffer == NULL)

  132.            type->tp_as_buffer = base->tp_as_buffer;

  133.    }

  134.    /* Link into each base class's list of subclasses */

  135.    bases = type->tp_bases;                                    // 获取初始化类型的基类列表,

  136.    n = PyTuple_GET_SIZE(bases);

  137.     for (i = 0; i < n; i++) {

  138.        PyObject *b = PyTuple_GET_ITEM(bases, i);            

  139.        if (PyType_Check(b) &&

  140.            add_subclass((PyTypeObject *)b, type) < 0)         // 将初始化类型添加到基类中,填充基类子类列表

  141.            goto error;

  142.    }

  143.    /* All done -- set the ready flag */

  144.    assert(type->tp_dict != NULL);

  145.    type->tp_flags =

  146.        (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;   // 设置该类型已经初始化完成

  147.    return 0;

  148.  error:

  149.    type->tp_flags &= ~Py_TPFLAGS_READYING;

  150.    return -1;

  151. }

其中,主要经历了五个不中

  1. 设置type信息,基类及基类列表;

  2. 填充tp_dict;

  3. 确定mro;

  4. 从mro列表继承基类属性;

  5. 设置基类的子类列表。 其中我们从初始化完成tp_dict后填充方法开始分析;

  1.    /* Add type-specific descriptors to tp_dict */

  2.    if (add_operators(type) < 0)                               // 给该类型添加描述方法

  3.        goto error;

  4.    if (type->tp_methods != NULL) {

  5.        if (add_methods(type, type->tp_methods) < 0)           // 如果类型方法不为空,则将方法包装后添加到初始化类型中

  6.            goto error;

  7.    }

  8.    if (type->tp_members != NULL) {

  9.        if (add_members(type, type->tp_members) < 0)           // 如果类型成员不为空,则将成员包装后添加到初始化类型中

  10.            goto error;

  11.    }

  12.    if (type->tp_getset != NULL) {

  13.        if (add_getset(type, type->tp_getset) < 0)            

  14.            goto error;

  15.    }

查看add_operators(type)方法;

  1. static int

  2. add_operators(PyTypeObject *type)

  3. {

  4.    PyObject *dict = type->tp_dict;

  5.    slotdef *p;

  6.    PyObject *descr;

  7.    void **ptr;

  8.    init_slotdefs ();                        // 排序slotdefs数组

  9.    for (p = slotdefs; p->name; p++) {      // 获取slotdefs的值

  10.        if (p->wrapper == NULL)             // 如果包装的函数为空,则直接获取下一个

  11.            continue;

  12.        ptr = slotptr(type, p->offset);     // 转换获取相应的方法

  13.        if (!ptr || !*ptr)

  14.            continue;

  15.        if (PyDict_GetItem(dict, p->name_strobj))   // 如果在属性列表中获取到相应名称,则不覆盖直接下一个

  16.            continue;

  17.        descr = PyDescr_NewWrapper(type, p, *ptr);   // 将该方法生成一个新的描述符

  18.        if (descr == NULL)

  19.            return -1;

  20.        if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)   // 将生成的描述符设置到对应的属性列表中

  21.            return -1;

  22.        Py_DECREF(descr);

  23.    }

  24.    if (type->tp_new != NULL) {

  25.        if (add_tp_new_wrapper(type) < 0)

  26.            return -1;

  27.    }

  28.    return 0;

  29. }

这其中出现了init_slotdefs,这在Python中有一个叫slot,一个slot对应一个方法。其定义如下;

  1. typedef struct wrapperbase slotdef;

  2. struct wrapperbase {

  3.    char *name;                 // 名称

  4.    int offset;                 // 偏移,相对于PyHead-TypeObject

  5.    void *function;             // 包装的函数

  6.    wrapperfunc wrapper;        

  7.    char *doc;                  // 文档

  8.    int flags;        

  9.    PyObject *name_strobj;     // 对应名称转换为字符串对象

  10. };

对于slotdef,提供了多种宏来定义一个slotdef

  1. #define FLSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC, FLAGS) \

  2.    {NAME, offsetof(PyTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \

  3.     PyDoc_STR(DOC), FLAGS}

  4. #define ETSLOT(NAME, SLOT, FUNCTION, WRAPPER, DOC) \

  5.    {NAME, offsetof(PyHeapTypeObject, SLOT), (void *)(FUNCTION), WRAPPER, \

  6.     PyDoc_STR(DOC)}

两个方法的不同就是一个相对于PyTypeObject,一个相对于PyHeapTypeObject,两个偏移量相对偏移的类型不同。其中PyHeapTypeObject定义如下;

  1. typedef struct _heaptypeobject {

  2.    /* Note: there's a dependency on the order of these members

  3.       in slotptr() in typeobject.c . */

  4.    PyTypeObject ht_type;

  5.    PyNumberMethods as_number;

  6.    PyMappingMethods as_mapping ;

  7.    PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,

  8.                      so that the mapping wins when both

  9.                      the mapping and the sequence define

  10.                      a given operator (e.g. __getitem__).

  11.                      see add_operators() in typeobject.c . */

  12.    PyBufferProcs as_buffer;

  13.    PyObject *ht_name, *ht_slots;

  14.    /* here are optional user slots, followed by the members. */

  15. } PyHeapTypeObject;

为什么会有这个区别是因为在一个PyTypeObject对象中,对应的操作方法比如nbadd是存放在函数指针tpasnumber中,而这是另外一个结构,无法计算出nbadd相对于PyTypeObject的相对位置,由PyHeapTypeObject可以看出,可以直接计算相对位置。 接下来查看下slotdefs数组;

  1. static slotdef slotdefs[] = {

  2.    SQSLOT("__len__", sq_length, slot_sq_length, wrap_lenfunc,

  3.           "x.__len__() <==> len(x)"),

  4.    /* Heap types defining __add__/__mul__ have sq_concat/sq_repeat == NULL.

  5.       The logic in abstract.c always falls back to nb_add/nb_multiply in

  6.       this case.  Defining both the nb_* and the sq_* slots to call the

  7.       user-defined methods has unexpected side-effects, as shown by

  8.       test_descr.notimplemented() */

  9.    SQSLOT("__add__", sq_concat, NULL, wrap_binaryfunc,

  10.          "x.__add__(y) <==> x+y"),

  11.    SQSLOT("__mul__", sq_repeat, NULL, wrap_indexargfunc,

  12.          "x.__mul__(n) <==> x*n"),

  13.    SQSLOT("__rmul__", sq_repeat, NULL, wrap_indexargfunc,

  14.          "x.__rmul__(n) <==> n*x"),

  15.     ...

  16.    SQSLOT("__getitem__", sq_item, slot_sq_item, wrap_sq_item,

  17.           "x.__getitem__(y) <==> x[y]"),

  18.    ...

  19.    MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,

  20.           wrap_binaryfunc,

  21.           "x.__getitem__(y) <==> x[y]"),

  22.    ...

  23. }

其中,可以发现有不同名的操作,也有同名的操作,对应于同名的操作是如何做选择呢,此时如果是PyTypeObject,此时相对于PyHeapTypeObject,其中asmapping在assequence上面,所有mpsubscript的排序会比sqitem靠前,所以会选择mpsubscript。 此时继续查看initslotdefs代码;

  1. static void

  2. init_slotdefs(void)

  3. {

  4.    slotdef *p;

  5.    static int initialized = 0;

  6.    if (initialized)

  7.        return;

  8.     for (p = slotdefs; p->name; p++) {

  9.        p->name_strobj = PyString_InternFromString(p->name);     // 将名称转换为Python内部字符串

  10.        if (!p->name_strobj)

  11.            Py_FatalError("Out of memory interning slotdef names");

  12.    }

  13.    qsort(( void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),

  14.          slotdef_cmp);                                         // 按照slot_cmp函数规则排序

  15.    initialized = 1;

  16. }

然后执行如下代码;

  1.    for (p = slotdefs; p->name; p++) {      // 获取slotdefs的值

  2.        if (p->wrapper == NULL)             // 如果包装的函数为空,则直接获取下一个

  3.            continue;

  4.        ptr = slotptr(type, p->offset);     // 转换获取相应的方法

  5.        if (!ptr || !*ptr)

  6.            continue;

  7.        if (PyDict_GetItem(dict, p->name_strobj))   // 如果在属性列表中获取到相应名称,则不覆盖直接下一个

  8.            continue;

  9.        descr = PyDescr_NewWrapper(type, p, *ptr);   // 将该方法生成一个新的描述符

  10.        if (descr == NULL)

  11.            return -1;

  12.        if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)   // 将生成的描述符设置到对应的属性列表中

  13.            return -1;

这里可以看到当需要在tpdict中设置属性时,并不是直接向slotdef直接设置到属性中,而是通过PyDescrNewWrapper生成一个描述符放置在tpdict中,为何要这么设计呢? 我们先查看PyDescrNewWrapper;

  1. PyObject *

  2. PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped)

  3. {

  4.    PyWrapperDescrObject *descr;

  5.    descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,

  6.                         type, base->name);

  7.    if (descr != NULL) {

  8.        descr->d_base = base;                // slotdef

  9.        descr->d_wrapped = wrapped;          // 被包装的函数

  10.    }

  11.    return (PyObject *)descr;

  12. }

继续查看descr_new;

  1. static PyDescrObject *

  2. descr_new(PyTypeObject * descrtype, PyTypeObject *type, const char *name)

  3. {

  4.    PyDescrObject *descr;

  5.    descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);

  6.    if (descr != NULL) {

  7.        Py_XINCREF(type);

  8.        descr->d_type = type;        // 设置装饰的类型

  9.        descr->d_name = PyString_InternFromString(name);  // 设置被装饰的名称

  10.        if (descr->d_name == NULL) {

  11.            Py_DECREF(descr);

  12.            descr = NULL;

  13.        }

  14.    }

  15.    return descr;

  16. }

由此查看PyDescrObject类型;

  1. #define PyDescr_COMMON \

  2.    PyObject_HEAD \

  3.    PyTypeObject *d_type; \

  4.    PyObject * d_name

  5. typedef struct {

  6.    PyDescr_COMMON;

  7.    struct wrapperbase *d_base;

  8.    void *d_wrapped; /* This can be any function pointer */

  9. } PyWrapperDescrObject;

由此可知一个descr是一个type类型的对象,为什么要转换为一个type类型呢,当调用tpdict的方法时,需要调用其中tpcall方法,而slotdef并不是一个可调用对象,并不符合可调用的要求。 在以上流程中,比较重要的就是怎样获取对应的ptr然后生成wrapper存入tp_dict中,

  1. ptr = slotptr(type, p ->offset);     // 转换获取相应的方法

对应的方法为

  1. static void **

  2. slotptr(PyTypeObject *type, int ioffset)

  3. {

  4.    char *ptr;

  5.    long offset = ioffset;

  6.     /* Note: this depends on the order of the members of PyHeapTypeObject! */

  7.    assert(offset >= 0);

  8.    assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer));

  9.    if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) {

  10.        ptr = (char *)type->tp_as_sequence ;

  11.        offset -= offsetof(PyHeapTypeObject, as_sequence);

  12.    }

  13.    else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) {

  14.        ptr = (char *)type->tp_as_mapping;

  15.        offset -= offsetof(PyHeapTypeObject , as_mapping);

  16.    }

  17.    else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) {

  18.        ptr = (char *)type->tp_as_number;

  19.        offset -= offsetof(PyHeapTypeObject, as_number);

  20.    }

  21.    else {

  22.        ptr = (char *)type;

  23.    }

  24.    if (ptr != NULL)

  25.        ptr += offset;

  26.    return (void **)ptr;

  27. }

此时,从上至下,依次是PyHeapTypeObject对应的assequence,asmapping,asnumber,这是因为offset的偏移是从大到小进行检查,因为assequence的距离是最远的,如果比assequence还小则再检查asmapping,如果比asmapping还小则检查asnumber,这样就可以查找出对应偏移量对应的方法。 此时tp dict属性字典方法填充完成。 当tpdict完成后类继承相关的操作 由于Python中的类的基础是一句传入的参数依次从左至右开始继承;

  1. >>> class A(object):

  2. ...     pass

  3. ...

  4. >>> class B(object):

  5. ...     pass

  6. ...

  7. >>> A.__mro__

  8. (<class '__main__.A'>, <type 'object'>)

  9. >>> class C(B,A):

  10. ...     pass

  11. ...

  12. >>> class D(C,A):

  13. ...     pass

  14. ...

  15. >>> D.__mro__

  16. (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

  17. >>> D.__bases__

  18. (<class '__main__.C'>, <class '__main__.A'>)

  19. >>> C.__mro__

  20. (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <type 'object'>)

  21. >>>

可见D的继承顺序是从左至右,依次继承初始化, 继承的代码执行流程如下;

  1.    /* Initialize tp_dict properly */

  2.    bases = type->tp_mro;                                      // 获取初始化类型的基础列表

  3.    assert(bases != NULL);    

  4.    assert(PyTuple_Check(bases));

  5.    n = PyTuple_GET_SIZE(bases);

  6.    for (i = 1; i < n; i++) {

  7.        PyObject *b = PyTuple_GET_ITEM(bases, i);              // 依次获取基础列表的值

  8.         if (PyType_Check(b))

  9.            inherit_slots(type, (PyTypeObject *)b);            // 继承相应的方法

  10.    }

由例子可知,tpmro的第一项是自身,所以i=1开始,依次获取对应的基类,然后执行,inheritslots,该函数主要就是检查基类中对应的方法子类中是否拥有,如果没有拥有则拷贝到子类中对应的方法中去,以此达到继承父类方法的功能,主要是一些方法的拷贝有兴趣可自行查看。 接着就将子类添加到基类的子类列表中

  1.    bases = type->tp_bases;                                    // 获取初始化类型的基类列表,

  2.    n = PyTuple_GET_SIZE(bases);

  3.    for ( i = 0; i < n; i++) {

  4.        PyObject *b = PyTuple_GET_ITEM(bases, i);            

  5.        if (PyType_Check(b) &&

  6.            add_subclass((PyTypeObject *)b, type) < 0)         // 将初始化类型添加到基类中,填充基类子类列表

  7.            goto error;

  8.    }

其中调用add_subclass时还生成了Python中的引用相关的操作,有兴趣课自行查看。 至此初始化就完成,一个PyTypeObject的初始化工作就已经完成,初始化内置类型的操作流程基本分析完成。

本文环境:Python2.5系列 

参考书籍:《Python源码剖析》

Python中文社区
全球Python中文开发者的
精神部落


Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以公安部、工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼ 点击下方阅读原文 免费成为社区会员


今天看啥 - 高品质阅读平台
本文地址:http://www.jintiankansha.me/t/fJzjHLsnFX
Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/19391
 
778 次点击