1- #### python集合
1+ # python集合
22
33set是无序且不重复的集合,是可变的,通常用来从列表中删除重复项以及计算数学运算,如交集、并集、差分和对称差分等集合操作。set 支持 x in set, len(set),和 for x in set。作为一个无序的集合,set不记录元素位置或者插入点。因此,sets不支持 indexing, 或其它类序列的操作。
44
5- #### python集合概述
5+ ## python集合概述
66
77在set中,对应的set的值的存储是通过结构setentry来保存数据值的;
88
9- ```
9+ 源文件: [ include/setobject.h ] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Include/setobject.h#L26 )
1010
11+ ```
1112typedef struct {
1213 PyObject *key;
1314 Py_hash_t hash; /* Cached hash code of the key */
@@ -16,6 +17,8 @@ typedef struct {
1617
1718key就是保存的数据,hash就是保存的数据的hash,便于查找,set也是基于hash表来实现。对应的setentry所对应的set的数据结构如下;
1819
20+ 源文件:[ include/setobject.h] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Include/setobject.h#L42 )
21+
1922```
2023
2124typedef struct {
@@ -48,7 +51,7 @@ typedef struct {
4851
4952![ 内存图片] ( ./python_set.png )
5053
51- #### python集合(set)示例
54+ ## python集合(set)示例
5255
5356示例脚本如下:
5457
@@ -115,10 +118,12 @@ python -m dis set_test.py
115118
116119通过该字节码指令可知,创建set调用了BUILD_SET指令,初始化完成之后,就调用set的add方法添加元素,调用remove删除元素,调用update来更新集合,通过union来合并集合。接下来就详细分析一下相关的操作流程。
117120
118- ##### set的创建与初始化
121+ ## set的创建与初始化
119122
120123查找BUILD_SET的虚拟机执行函数如下;
121124
125+ 源文件:[ Python/ceval.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Python/ceval.c#L2318 )
126+
122127```
123128// Python/ceval.c
124129
@@ -147,6 +152,8 @@ python -m dis set_test.py
147152
148153此时继续查看PySet_New函数的执行流程;
149154
155+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L2286 )
156+
150157
151158```
152159PyObject *
@@ -188,10 +195,12 @@ make_new_set(PyTypeObject *type, PyObject *iterable)
188195
189196从PySet_New的执行流程可知,字典的初始化过程就是初始化相关数据结构。
190197
191- ##### set的插入
198+ ## set的插入
192199
193200在本例的初始化过程中,由于传入了初始值1,2,所以会在执行字节码指令的时候,执行PySet_Add,该函数的本质与set_a.add(3)本质都调用了更底层set_add_key函数;
194201
202+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L2338 )
203+
195204```
196205
197206int
@@ -208,6 +217,8 @@ PySet_Add(PyObject *anyset, PyObject *key)
208217
209218继续查看set_add_key函数的执行过程;
210219
220+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L419 )
221+
211222```
212223static int
213224set_add_key(PySetObject *so, PyObject *key)
@@ -226,6 +237,8 @@ set_add_key(PySetObject *so, PyObject *key)
226237
227238该函数主要就是检查传入的key是否能够被hash,如果能够被hash则直接返回,如果能被hash则继续调用set_add_entry函数将值加入到set中;
228239
240+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L136 )
241+
229242```
230243
231244static int
@@ -375,10 +388,12 @@ s.add(7) // index = 9 & 7 = 1
375388
376389大致的set的插入过程执行完毕。
377390
378- ##### set的删除
391+ ## set的删除
379392
380393set的删除操作主要集中在set_remove()函数上,如下示例;
381394
395+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L1921 )
396+
382397```
383398
384399static PyObject *
@@ -411,6 +426,8 @@ set_remove(PySetObject *so, PyObject *key)
411426
412427此时就会调用set_discard_key方法来讲对应的entry设置为dummy;set_discard_key方法如下;
413428
429+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L447 )
430+
414431```
415432
416433static int
@@ -430,6 +447,8 @@ set_discard_key(PySetObject *so, PyObject *key)
430447
431448该函数主要就是做了检查key是否可用hash的检查,此时如果可用hash则调用set_discard_entry方法;
432449
450+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L400 )
451+
433452```
434453
435454static int
@@ -454,11 +473,12 @@ set_discard_entry(PySetObject *so, PyObject *key, Py_hash_t hash)
454473
455474此时就是查找该值,如果找到该值并将该值设置为dummy,并且将used值减1,此处没有减去fill的数量,从此处可知,fill包括所有曾经申请过的数量。
456475
457-
458- ##### set的resize
476+ ## set的resize
459477
460478set的resize主要依靠set_table_reseize函数来实现;
461479
480+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L302 )
481+
462482```
463483static int
464484set_table_resize(PySetObject *so, Py_ssize_t minused)
@@ -543,6 +563,8 @@ set_table_resize(PySetObject *so, Py_ssize_t minused)
543563
544564主要是检查是否table相同并且需要重新resize的值,然后判断是否fill与used相同,如果相同则全部插入,如果不同,则遍历旧table讲不为空并且不为dummy的值插入到新表中;
545565
566+ 源文件:[ Objects/setobject.c] ( https://github.com/python/cpython/blob/1bf9cc509326bc42cd8cb1650eb9bf64550d817e/Objects/setobject.c#L267 )
567+
546568```
547569static void
548570set_insert_clean(setentry *table, size_t mask, PyObject *key, Py_hash_t hash)
0 commit comments