Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1684f28

Browse files
committed
update
1 parent 9eba27a commit 1684f28

File tree

1 file changed

+217
-0
lines changed

1 file changed

+217
-0
lines changed

‎ch02.md‎

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,218 @@
11
# Pyhton 中的整数对象
2+
3+
PyIntObject 的定义:
4+
5+
```C
6+
typedef struct {
7+
PyObject_HEAD
8+
long ob_ival;
9+
} PyIntObject;
10+
```
11+
12+
`ob_ival` 存放 int 对象实际的值。
13+
14+
PyInt_Type 的定义:
15+
16+
```C
17+
PyTypeObject PyInt_Type = {
18+
PyObject_HEAD_INIT(&PyType_Type)
19+
0,
20+
"int",
21+
sizeof(PyIntObject),
22+
0,
23+
(destructor)int_dealloc, /* tp_dealloc */
24+
(printfunc)int_print, /* tp_print */
25+
0, /* tp_getattr */
26+
0, /* tp_setattr */
27+
(cmpfunc)int_compare, /* tp_compare */
28+
(reprfunc)int_repr, /* tp_repr */
29+
&int_as_number, /* tp_as_number */
30+
0, /* tp_as_sequence */
31+
0, /* tp_as_mapping */
32+
(hashfunc)int_hash, /* tp_hash */
33+
0, /* tp_call */
34+
(reprfunc)int_repr, /* tp_str */
35+
PyObject_GenericGetAttr, /* tp_getattro */
36+
0, /* tp_setattro */
37+
0, /* tp_as_buffer */
38+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
39+
Py_TPFLAGS_BASETYPE, /* tp_flags */
40+
int_doc, /* tp_doc */
41+
0, /* tp_traverse */
42+
0, /* tp_clear */
43+
0, /* tp_richcompare */
44+
0, /* tp_weaklistoffset */
45+
0, /* tp_iter */
46+
0, /* tp_iternext */
47+
int_methods, /* tp_methods */
48+
0, /* tp_members */
49+
0, /* tp_getset */
50+
0, /* tp_base */
51+
0, /* tp_dict */
52+
0, /* tp_descr_get */
53+
0, /* tp_descr_set */
54+
0, /* tp_dictoffset */
55+
0, /* tp_init */
56+
0, /* tp_alloc */
57+
int_new, /* tp_new */
58+
(freefunc)int_free, /* tp_free */
59+
};
60+
```
61+
62+
`int_as_number` 结构体中定义了许多整数操作相关的函数,特别讨论一下其中的 `int_add`,代码如下:
63+
64+
```C
65+
static PyObject *
66+
int_add(PyIntObject *v, PyIntObject *w)
67+
{
68+
register long a, b, x;
69+
CONVERT_TO_LONG(v, a);
70+
CONVERT_TO_LONG(w, b);
71+
x = a + b;
72+
if ((x^a) >= 0 || (x^b) >= 0)
73+
return PyInt_FromLong(x);
74+
return PyLong_Type.tp_as_number->nb_add((PyObject *)v, (PyObject *)w);
75+
}
76+
```
77+
78+
`int_add` 这段代码有几个需要注意的点:
79+
80+
- `if ((x^a) >= 0 || (x^b) >= 0)`
81+
82+
判断两整数相加的结果是否溢出。整数相加只有在符号位相同时才会可能发生溢出,这里的 if 判断结果的符号位和两整数的符号位是否一致。
83+
84+
- 如果相加结果溢出,则使用 PyLong_Type 的 nb_add 对两数求和。
85+
86+
## 创建整数对象
87+
88+
- `PyObject* PyInt_FromLong(long ival)`
89+
90+
- `PyObject* PyInt_FromString(char *s, char **pend, int base)`
91+
92+
- `PyObject*PyInt_FromUnicode(Py_UNICODE *s, int length, int base)`
93+
94+
重点查看 `PyInt_FromLong` 的代码,其它两种最终都是调用 `PyInt_FromLong` 创建整数对象的。
95+
96+
### 小整数对象池
97+
98+
小整数的使用频率非常高,如果每次使用小整数时都需要初始化 PyIntObject,将导致频繁调用 malloc 分配内存,这显然会影响代码的效率。在 Python 中使用小整数对象池技术避免了这个问题。
99+
100+
Python 会预先将初始化好的小整数对象存放到一个数组中,代码如下:
101+
102+
```C
103+
// 定义小整数对象池
104+
105+
#ifndef NSMALLPOSINTS
106+
#define NSMALLPOSINTS 257
107+
#endif
108+
#ifndef NSMALLNEGINTS
109+
#define NSMALLNEGINTS 5
110+
#endif
111+
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
112+
/* References to small integers are saved in this array so that they
113+
can be shared.
114+
The integers that are saved are those in the range
115+
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
116+
*/
117+
static PyIntObject *small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
118+
#endif
119+
120+
```
121+
122+
在 Python2.5 中,正整数个数为 257,负整数的个数为 5。
123+
124+
### 大整数对象池
125+
126+
Python 内部使用 PyIntBlock 来管理大整数对象,一个 block 里面可以保存一定数量的整数。
127+
PyIntBlock 的定义如下:
128+
129+
```C
130+
/* Integers are quite normal objects, to make object handling uniform.
131+
(Using odd pointers to represent integers would save much space
132+
but require extra checks for this special case throughout the code.)
133+
Since a typical Python program spends much of its time allocating
134+
and deallocating integers, these operations should be very fast.
135+
Therefore we use a dedicated allocation scheme with a much lower
136+
overhead (in space and time) than straight malloc(): a simple
137+
dedicated free list, filled when necessary with memory from malloc().
138+
139+
block_list is a singly-linked list of all PyIntBlocks ever allocated,
140+
linked via their next members. PyIntBlocks are never returned to the
141+
system before shutdown (PyInt_Fini).
142+
143+
free_list is a singly-linked list of available PyIntObjects, linked
144+
via abuse of their ob_type members.
145+
*/
146+
147+
#define BLOCK_SIZE 1000 /* 1K less typical malloc overhead */
148+
#define BHEAD_SIZE 8 /* Enough for a 64-bit pointer */
149+
#define N_INTOBJECTS ((BLOCK_SIZE - BHEAD_SIZE) / sizeof(PyIntObject))
150+
151+
struct _intblock {
152+
struct _intblock *next;
153+
PyIntObject objects[N_INTOBJECTS];
154+
};
155+
156+
typedef struct _intblock PyIntBlock;
157+
158+
static PyIntBlock *block_list = NULL;
159+
static PyIntObject *free_list = NULL;
160+
```
161+
162+
### PyInt_FromLong
163+
164+
PyInt_FromLong 的作用是将 C 语言中 long 类型的整数转换为 PyIntObject。代码如下:
165+
166+
```C
167+
[intobject.c]
168+
PyObject* PyInt_FromLong(long ival)
169+
{
170+
register PyIntObject *v;
171+
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
172+
//[1] :尝试使用小整数对象池
173+
if (-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS) {
174+
v = small_ints[ival + NSMALLNEGINTS];
175+
Py_INCREF(v);
176+
return (PyObject *) v;
177+
}
178+
#endif
179+
//[2] :为通用整数对象池申请新的内存空间
180+
if (free_list == NULL) {
181+
if ((free_list = fill_free_list()) == NULL)
182+
return NULL;
183+
}
184+
//[3] : (inline) 内联 PyObject_New 的行为
185+
v = free_list;
186+
free_list = (PyIntObject *)v->ob_type;
187+
PyObject_INIT(v, &PyInt_Type);
188+
v->ob_ival = ival;
189+
return (PyObject *) v;
190+
}
191+
```
192+
193+
fill_free_list 代码如下:
194+
195+
```C
196+
static PyIntObject *
197+
fill_free_list(void)
198+
{
199+
PyIntObject *p, *q;
200+
/* Python's object allocator isn't appropriate for large blocks. */
201+
p = (PyIntObject *) PyMem_MALLOC(sizeof(PyIntBlock));
202+
if (p == NULL)
203+
return (PyIntObject *) PyErr_NoMemory();
204+
((PyIntBlock *)p)->next = block_list;
205+
block_list = (PyIntBlock *)p;
206+
/* Link the int objects together, from rear to front, then return
207+
the address of the last int object in the block. */
208+
p = &((PyIntBlock *)p)->objects[0];
209+
q = p + N_INTOBJECTS;
210+
while (--q> p)
211+
q->ob_type = (struct _typeobject *)(q-1);
212+
q->ob_type = NULL;
213+
return p + N_INTOBJECTS - 1;
214+
}
215+
```
216+
217+
上面 `fill_free_list` 函数中,为了将 `PyIntBlock.objects` 转换成单向链表,对 `objects` 中元素进行强制类型转换,并将 `ob_type` 当做连接器(next),违反了类型安全。
218+

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /