社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

Python源码分析:类的机制

Python中文社区 • 7 年前 • 992 次点击  

--  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
 
992 次点击