Skip to content

Commit 48eb16a

Browse files
committed
新增「元组对象」章节,并为其余对象章节补全配图
- 新增元组对象章节:数据结构、创建(free list/BUILD_TUPLE)、索引与切片、 拼接重复与比较、打包与解包、不可变与可哈希、与列表的取舍,配 6 张图 - 补图:整数(小整数池、创建分派)、对象初探(多态、协议族、引用计数)、 字符串(跳跃式查找)、列表(free_list 缓冲池),共 7 张 - 接入侧边栏、Roadmap、SUMMARY
1 parent 482cda3 commit 48eb16a

21 files changed

Lines changed: 946 additions & 0 deletions

.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export default defineConfig({
5151
{ text: 'Python 整数对象', link: '/objects/long-object/' },
5252
{ text: 'Python 字符串对象', link: '/objects/str-object/' },
5353
{ text: 'Python 列表对象', link: '/objects/list-object/' },
54+
{ text: 'Python 元组对象', link: '/objects/tuple-object/' },
5455
{ text: 'Python 字典对象', link: '/objects/dict-object/' },
5556
{ text: 'Python 集合对象', link: '/objects/set-object/' },
5657
{ text: '实现简版 Python', link: '/objects/simple-interpreter/' }

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- [Python 整数对象](objects/long-object/index.md)
1515
- [Python 字符串 对象](objects/string-object/index.md)
1616
- [Python List 对象](objects/list-object/index.md)
17+
- [Python 元组对象](objects/tuple-object/index.md)
1718
- [Python Dict 对象](objects/dict-object/index.md)
1819
- [Python Set 对象](objects/set-object/index.md)
1920
- [实现简版 Python](objects/simple-interpreter/index.md)

index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [x] Python 整数对象
2121
- [x] Python 字符串对象
2222
- [x] Python 列表对象
23+
- [x] Python 元组对象
2324
- [x] Python 字典对象
2425
- [x] Python 集合对象
2526
- [ ] 实现简版 Python

objects/list-object/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ PyList_New(Py_ssize_t size)
9090
9191
注意这里复用的只是 `PyListObject` 这个「壳」(对象头那部分),存放元素的 `ob_item` 数组仍按需另行申请。
9292
93+
![列表的创建与缓冲池](list-create.svg)
94+
9395
## 列表的下标存取
9496
9597
下标访问之所以快,是因为它直接落到 `ob_item[i]`,没有任何查找:
Lines changed: 42 additions & 0 deletions
Loading

objects/long-object/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
160160

161161
所以默认的小整数范围是 **[-5, 257)**,也就是 -5 到 256。256 落在池内,于是 `a``b` 拿到的是同一个对象;257 在池外,每次都是新建,自然就不是同一个了。
162162

163+
![小整数对象池](int-smallpool.svg)
164+
163165
需要时如何从池中取?看 `get_small_int` 和配套的宏 `CHECK_SMALL_INT`
164166

165167
`源文件:`[Objects/longobject.c](https://github.com/python/cpython/blob/v3.7.0/Objects/longobject.c#L49)
@@ -254,6 +256,8 @@ long_new_impl(PyTypeObject *type, PyObject *x, PyObject *obase)
254256

255257
对应到 Python 里就是 `int()``int(x)``int("10", 8)` 这几种用法:无参返回 0;只给一个对象就按其类型转换;再给一个进制,就把字符串/字节串按该进制解析。
256258

259+
![整数创建的分派](int-create.svg)
260+
257261
## 整数的数值操作
258262

259263
整数「能做哪些运算」,记录在它类型对象的 `tp_as_number` 所指向的 `long_as_number` 里——这张表的每个槽位对应一种运算,填的是具体的实现函数:

objects/long-object/int-create.svg

Lines changed: 41 additions & 0 deletions
Loading
Lines changed: 45 additions & 0 deletions
Loading

objects/object/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ PyTypeObject PyLong_Type = {
352352

353353
于是,当你写下 `a + b``a` 是整数时,解释器最终会顺着 `a->ob_type->tp_as_number->nb_add` 找到 `long_add` 并调用它。`tp_as_sequence``tp_as_mapping` 的套路完全一样,分别对应序列和映射的操作,这里不再展开。
354354

355+
![对象的行为:协议族](obj-protocols.svg)
356+
355357
## 对象的多态
356358

357359
把上面的机制再抽象一层,就能理解 CPython 是怎样实现**多态**的。
@@ -401,6 +403,8 @@ PyTypeObject PyUnicode_Type = {
401403

402404
同一行 `object->ob_type->tp_hash(object)`,对整数和字符串却走进了不同的实现——这就是 CPython 用 C 语言「手工」实现的多态。
403405

406+
![对象的多态](obj-polymorphism.svg)
407+
404408
## 引用计数
405409

406410
最后回到对象头里的另一个字段 `ob_refcnt`。CPython 用**引用计数**来决定一个对象在内存中的生死:每个对象都记录着「当前有多少处引用着我」,当这个数归零,对象就可以被回收。
@@ -453,6 +457,8 @@ PyTypeObject PyUnicode_Type = {
453457

454458
`sys.getrefcount` 的返回值总比「真实」引用数多 1,因为把对象作为参数传进函数这一动作本身,就临时多产生了一次引用。
455459

460+
![引用计数与销毁](obj-refcount.svg)
461+
456462
需要强调的是:引用计数归零,**不一定**马上 `free` 掉内存。频繁向操作系统申请、释放内存会显著拖慢 Python,因此 CPython 大量使用**内存对象池**技术——对象「销毁」时,其占用的空间往往被归还给对象池而非真正释放,下次创建同类对象时可以直接复用。小整数、短字符串等都受益于这类优化,具体策略我们会在各对象章节里逐一剖析。
457463

458464
---

0 commit comments

Comments
 (0)