forked from zpoint/CPython-Internals
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtuple.md
More file actions
118 lines (81 loc) · 3.27 KB
/
Copy pathtuple.md
File metadata and controls
118 lines (81 loc) · 3.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# tuple
# contents
* [related file](#related-file)
* [memory layout](#memory-layout)
* [how element stored inside](#how-element-stored-inside)
* [free list](#free-list)
# related file
* cpython/Include/cpython/tupleobject.c
* cpython/Include/tupleobject.h
* cpython/Objects/tupleobject.c
# memory layout

The structure of **tuple** object is more simple than other python object.
Obviously, **ob_item** is an array of PyObject* pointer, all elements will be stored inside the **ob_item** array, But how exactly each element stored in **PyTupleObject**? Is the first element begin at the 0 index? What is the resize strategy?
Let's see
# how element stored inside
```python3
t = tuple()
```

```python3
t = ("aa", )
```

```python3
t = ("aa", "bb", "cc", "dd")
```
**ob_size** represents the size of **PyTupleObject** object, because tuple object is immutable, the **ob_item** is the start address of an array of pointer to **PyObject**, and the size of this array is **ob_size**, there's no need for resize operation.

# free list
The free_list mechanism used here is more interesting than [free_list in list](https://github.com/zpoint/CPython-Internals/blob/master/BasicObject/list/list.md#delete-and-free-list)
```c
#define PyTuple_MAXSAVESIZE 20
#define PyTuple_MAXFREELIST 2000
static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
static int numfree[PyTuple_MAXSAVESIZE];
```
let's exam what **free_list** and **numfree** is
we assume that python interpreter don't create/deallocate any tuple object internally during the following code
```python3
>>> t = tuple()
>>> id(t)
4458758208
>>> del t
>>> t = tuple()
>>> id(t) # same as previous deleted one
4458758208
>>> t2 = tuple()
>>> id(t2) # same as t
4458758208
```

```python3
>>> t = ("aa", )
>>> id(t)
4459413360
>>> del t
>>> t = ("bb", )
>>> id(t) # it's not repeatable, because I assume that python intepreter don't create/deallocate any tuple object during execution
4459413360
>>> t2 = ("cc", )
>>> del t
>>> del t2
```

num_free[i] means how many objects left in free_list[i], when you create a new tuple with size i, cpython will use the top object at free_list[i]
```python3
>>> t = ("aa", )
```

```python3
>>> t2 = ("aa", "bb")
>>> t3 = ("cc", "dd")
>>> t4 = ("ee", "ff")
>>> t5 = ("gg", "hh")
>>> del t2
>>> del t3
>>> del t4
>>> del t5
```
