文档备案控制台
免费开始使用

Python源码分析:类的机制

picture.image

-- 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. 
7. `if (PyType_Ready(&_PyWeakref_RefType) < 0)`
8. `Py_FatalError("Can't initialize 'weakref'");`
9. 
10. `if (PyType_Ready(&PyBool_Type) < 0)`
11. `Py_FatalError("Can't initialize 'bool'");`
12. 
13. `if (PyType_Ready(&PyString_Type) < 0)`
14. `Py_FatalError("Can't initialize 'str'");`
15. 
16. `if (PyType_Ready(&PyList_Type) < 0)`
17. `Py_FatalError("Can't initialize 'list'");`
18. 
19. `if (PyType_Ready(&PyNone_Type) < 0)`
20. `Py_FatalError("Can't initialize type(None)");`
21. 
22. `if (PyType_Ready(&PyNotImplemented_Type) < 0)`
23. `Py_FatalError("Can't initialize type(NotImplemented)");`
24. `}`


    

这里分析下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. 
8. `if (type->tp_flags & Py_TPFLAGS_READY) {`
9. `assert(type->tp_dict != NULL);`
10. `return 0;`
11. `}`
12. `assert((type->tp_flags & Py_TPFLAGS_READYING) == 0);`
13. 
14. `type->tp_flags |= Py_TPFLAGS_READYING;`
15. 
16. `#ifdef Py_TRACE_REFS`
17. `/* PyType_Ready is the closest thing we have to a choke point`
18. `* for type objects, so is the best place I can think of to try`
19. `* to get type objects into the doubly-linked list of all objects.`
20. `* Still, not all type objects go thru PyType_Ready.`
21. `*/`
22. `_Py_AddToAllObjects((PyObject *)type, 0);`
23. `#endif`
24. 
25. `/* Initialize tp_base (defaults to BaseObject unless that's us) */`
26. `base = type->tp_base;                                       // 获取初始化类型的基类`
27. `if (base == NULL && type != &PyBaseObject_Type) {           // 如果基类为空,并且初始化的类型不为Object`
28. `base = type->tp_base = &PyBaseObject_Type;              // 将初始化类的基类设置成Object`
29. `Py_INCREF(base);`
30. `}`
31. 
32. `/* Now the only way base can still be NULL is if type is`
33. `* &PyBaseObject_Type.`
34. `*/`
35. 
36. `/* Initialize the base class */`
37. `if (base && base->tp_dict == NULL) {                        // 如果基类的属性列表为空`
38. `if (PyType_Ready(base) < 0)                             // 初始化基类`
39. `goto error;`
40. `}`
41. 
42. `/* Initialize ob_type if NULL.  This means extensions that want to be`
43. `compilable separately on Windows can call PyType_Ready() instead of`
44. `initializing the ob_type field of their type objects. */`
45. `/* The test for base != NULL is really unnecessary, since base is only`
46. `NULL when type is &PyBaseObject_Type, and we know its ob_type is`
47. `not NULL (it's initialized to &PyType_Type).  But coverity doesn't`
48. `know that. */`
49. `if (type->ob_type == NULL && base != NULL)                 // 如果初始化类型的类型为空,并且基类不为空`
50. `type->ob_type = base->ob_type;                         // 初始化类型的类型设置成基类的类型`
51. 
52. `/* Initialize tp_bases */`
53. `bases = type->tp_bases;                                    // 获取初始化类型的基类列表`
54. `if (bases == NULL) {                                       // 如果基类列表为空`
55. `if (base == NULL)                                      // 如果父类为空`
56. `bases = PyTuple_New(0);                            // 基类则生成一个空的元组`
57. `else`
58. `bases = PyTuple_Pack(1, base);                     // 如果基类不为空,生成长度为1的元组,并将base发入其中`
59. `if (bases == NULL)`
60. `goto error;`
61. `type->tp_bases = bases;                                // 将生成的bases设置到初始化类型中`
62. `}`
63. 
64. `/* Initialize tp_dict */`
65. `dict = type->tp_dict;                                      // 获取类型的属性列表`
66. `if (dict == NULL) {`
67. `dict = PyDict_New();                                   // 如果属性为空,则生成一个字典,并设置到初始化类型中`
68. `if (dict == NULL)`
69. `goto error;`
70. `type->tp_dict = dict;`
71. `}`
72. 
73. `/* Add type-specific descriptors to tp_dict */`
74. `if (add_operators(type) < 0)                               // 给该类型添加描述方法`
75. `goto error;`
76. `if (type->tp_methods != NULL) {`
77. `if (add_methods(type, type->tp_methods) < 0)           // 如果类型方法不为空,则将方法包装后添加到初始化类型中`
78. `goto error;`
79. `}`
80. `if (type->tp_members != NULL) {`
81. `if (add_members(type, type->tp_members) < 0)           // 如果类型成员不为空,则将成员包装后添加到初始化类型中`
82. `goto error;`
83. `}`
84. `if (type->tp_getset != NULL) {`
85. `if (add_getset(type, type->tp_getset) < 0)`
86. `goto error;`
87. `}`
88. 
89. `/* Calculate method resolution order */`
90. `if (mro_internal(type) < 0) {                              // 获取初始化类型的基础列表`
91. `goto error;`
92. `}`
93. 
94. `/* Inherit special flags from dominant base */`
95. `if (type->tp_base != NULL)`
96. `inherit_special(type, type->tp_base);                  // 如果基类不为空,则继承基类的方法属性等`
97. 
98. `/* Initialize tp_dict properly */`
99. `bases = type->tp_mro;                                      // 获取初始化类型的基础列表`
100. `assert(bases != NULL);`
101. `assert(PyTuple_Check(bases));`
102. `n = PyTuple_GET_SIZE(bases);`
103. `for (i = 1; i < n; i++) {`
104. `PyObject *b = PyTuple_GET_ITEM(bases, i);              // 依次获取基础列表的值`
105. `if (PyType_Check(b))`
106. `inherit_slots(type, (PyTypeObject *)b);            // 继承相应的方法`
107. `}`
108. 
109. `/* Sanity check for tp_free. */`
110. `if (PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) &&`
111. `(type->tp_free == NULL || type->tp_free == PyObject_Del)) {`
112. `/* This base class needs to call tp_free, but doesn't have`
113. `* one, or its tp_free is for non-gc'ed objects.`
114. `*/`
115. `PyErr_Format(PyExc_TypeError, "type '%.100s' participates in "`
116. `"gc and is a base type but has inappropriate "`
117. `"tp_free slot",`
118. `type->tp_name);`
119. `goto error;`
120. `}`
121. 
122. `/* if the type dictionary doesn't contain a __doc__, set it from`
123. `the tp_doc slot.`
124. `*/`
125. `if (PyDict_GetItemString(type->tp_dict, "__doc__") == NULL) {    // 设置属性的__doc__属性,如果有设置其中,如果没有则设置为空`
126. `if (type->tp_doc != NULL) {`
127. `PyObject *doc = PyString_FromString(type->tp_doc);`
128. `if (doc == NULL)`
129. `goto error;`
130. `PyDict_SetItemString(type->tp_dict, "__doc__", doc);`
131. `Py_DECREF(doc);`
132. `} else {`
133. `PyDict_SetItemString(type->tp_dict,`
134. `"__doc__", Py_None);`
135. `}`
136. `}`
137. 
138. `/* Some more special stuff */`
139. `base = type->tp_base;                                       // 获取基类,如果子类相应的方法为空,则直接将基类方法设置给初始化类型`
140. `if (base != NULL) {`
141. `if (type->tp_as_number == NULL)`
142. `type->tp_as_number = base->tp_as_number;`
143. `if (type->tp_as_sequence == NULL)`
144. `type->tp_as_sequence = base->tp_as_sequence;`
145. `if (type->tp_as_mapping == NULL)`
146. `type->tp_as_mapping = base->tp_as_mapping;`
147. `if (type->tp_as_buffer == NULL)`
148. `type->tp_as_buffer = base->tp_as_buffer;`
149. `}`
150. 
151. `/* Link into each base class's list of subclasses */`
152. `bases = type->tp_bases;                                    // 获取初始化类型的基类列表,`
153. `n = PyTuple_GET_SIZE(bases);`
154. `for (i = 0; i < n; i++) {`
155. `PyObject *b = PyTuple_GET_ITEM(bases, i);`
156. `if (PyType_Check(b) &&`
157. `add_subclass((PyTypeObject *)b, type) < 0)         // 将初始化类型添加到基类中,填充基类子类列表`
158. `goto error;`
159. `}`
160. 
161. `/* All done -- set the ready flag */`
162. `assert(type->tp_dict != NULL);`
163. `type->tp_flags =`
164. `(type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY;   // 设置该类型已经初始化完成`
165. `return 0;`
166. 
167. `error:`
168. `type->tp_flags &= ~Py_TPFLAGS_READYING;`
169. `return -1;`
170. `}`


    

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

  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. 
9. `init_slotdefs();                        // 排序slotdefs数组`
10. `for (p = slotdefs; p->name; p++) {      // 获取slotdefs的值`
11. `if (p->wrapper == NULL)             // 如果包装的函数为空,则直接获取下一个`
12. `continue;`
13. `ptr = slotptr(type, p->offset);     // 转换获取相应的方法`
14. `if (!ptr || !*ptr)`
15. `continue;`
16. `if (PyDict_GetItem(dict, p->name_strobj))   // 如果在属性列表中获取到相应名称,则不覆盖直接下一个`
17. `continue;`
18. `descr = PyDescr_NewWrapper(type, p, *ptr);   // 将该方法生成一个新的描述符`
19. `if (descr == NULL)`
20. `return -1;`
21. `if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)   // 将生成的描述符设置到对应的属性列表中`
22. `return -1;`
23. `Py_DECREF(descr);`
24. `}`
25. `if (type->tp_new != NULL) {`
26. `if (add_tp_new_wrapper(type) < 0)`
27. `return -1;`
28. `}`
29. `return 0;`
30. `}`


    

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


      1. `typedef struct wrapperbase slotdef;`
2. 
3. `struct wrapperbase {`
4. `char *name;                 // 名称`
5. `int offset;                 // 偏移,相对于PyHead-TypeObject`
6. `void *function;             // 包装的函数`
7. `wrapperfunc wrapper;`
8. `char *doc;                  // 文档`
9. `int flags;`
10. `PyObject *name_strobj;     // 对应名称转换为字符串对象`
11. `};`


    

对于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. 
7. `if (initialized)`
8. `return;`
9. `for (p = slotdefs; p->name; p++) {`
10. `p->name_strobj = PyString_InternFromString(p->name);     // 将名称转换为Python内部字符串`
11. `if (!p->name_strobj)`
12. `Py_FatalError("Out of memory interning slotdef names");`
13. `}`
14. `qsort((void *)slotdefs, (size_t)(p-slotdefs), sizeof(slotdef),`
15. `slotdef_cmp);                                         // 按照slot_cmp函数规则排序`
16. `initialized = 1;`
17. `}`


    

然后执行如下代码;


      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. 
6. `descr = (PyWrapperDescrObject *)descr_new(&PyWrapperDescr_Type,`
7. `type, base->name);`
8. `if (descr != NULL) {`
9. `descr->d_base = base;                // slotdef`
10. `descr->d_wrapped = wrapped;          // 被包装的函数`
11. `}`
12. `return (PyObject *)descr;`
13. `}`


    

继续查看descr_new;


      1. `static PyDescrObject *`
2. `descr_new(PyTypeObject *descrtype, PyTypeObject *type, const char *name)`
3. `{`
4. `PyDescrObject *descr;`
5. 
6. `descr = (PyDescrObject *)PyType_GenericAlloc(descrtype, 0);`
7. `if (descr != NULL) {`
8. `Py_XINCREF(type);`
9. `descr->d_type = type;        // 设置装饰的类型`
10. `descr->d_name = PyString_InternFromString(name);  // 设置被装饰的名称`
11. `if (descr->d_name == NULL) {`
12. `Py_DECREF(descr);`
13. `descr = NULL;`
14. `}`
15. `}`
16. `return descr;`
17. `}`


    

由此查看PyDescrObject类型;


      1. `#define PyDescr_COMMON \`
2. `PyObject_HEAD \`
3. `PyTypeObject *d_type; \`
4. `PyObject *d_name`
5. 
6. `typedef struct {`
7. `PyDescr_COMMON;`
8. `struct wrapperbase *d_base;`
9. `void *d_wrapped; /* This can be any function pointer */`
10. `} 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. 
7. `/* Note: this depends on the order of the members of PyHeapTypeObject! */`
8. `assert(offset >= 0);`
9. `assert((size_t)offset < offsetof(PyHeapTypeObject, as_buffer));`
10. `if ((size_t)offset >= offsetof(PyHeapTypeObject, as_sequence)) {`
11. `ptr = (char *)type->tp_as_sequence;`
12. `offset -= offsetof(PyHeapTypeObject, as_sequence);`
13. `}`
14. `else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_mapping)) {`
15. `ptr = (char *)type->tp_as_mapping;`
16. `offset -= offsetof(PyHeapTypeObject, as_mapping);`
17. `}`
18. `else if ((size_t)offset >= offsetof(PyHeapTypeObject, as_number)) {`
19. `ptr = (char *)type->tp_as_number;`
20. `offset -= offsetof(PyHeapTypeObject, as_number);`
21. `}`
22. `else {`
23. `ptr = (char *)type;`
24. `}`
25. `if (ptr != NULL)`
26. `ptr += offset;`
27. `return (void **)ptr;`
28. `}`


    

此时,从上至下,依次是PyHeapTypeObject对应的assequence,asmapping,asnumber,这是因为offset的偏移是从大到小进行检查,因为assequence的距离是最远的,如果比assequence还小则再检查asmapping,如果比asmapping还小则检查asnumber,这样就可以查找出对应偏移量对应的方法。 此时tpdict属性字典方法填充完成。 当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源码剖析》

picture.image

Python中文社区

全球Python中文开发者的

精神部落

picture.image.jpg")

picture.image

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

picture.image

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

0
0
0
0
评论
未登录
暂无评论