Python万物皆对象理解及源码学习

发布时间:2026/10/28 20:12:03
Python万物皆对象理解及源码学习 前言先纠正一句被传得太广的话「Python 万物皆对象」是一个简化口号并不严格准确。官方数据模型的准确说法是Python 程序里的数据都由对象或对象之间的关系表示连代码都是对象但语言语法层面的东西——关键字if、for、运算符、is、语句结构、缩进——是文法的组成部分不是对象变量名也不是对象它只是一个「名字到对象的绑定」。所以更严谨的说法是Python 里几乎所有你可以操作的东西都是对象而不是字面意义上的万物。第二个需要说清的背景是「源码学习」。CPython 是 Python 的参考实现它的源码用 C 写核心是「每个 Python 对象在 C 层都是一个结构体」。本文只能从官方文档给出的行为去反推这套实现本机既没有 Python 解释器也没有 C 编译器无法编译或实际运行任何示例涉及实现细节的地方我会明确标注「是实现细节不要依赖」。文中所有输出均为按文档规则人工推演。一、对象的三要素标识、类型、值官方定义得很干脆每个对象都有标识identity、类型type和值value。标识一经创建就不再改变可以理解为对象在内存里的地址is比较的是标识id()返回的是标识对应的整数。类型决定这个对象支持哪些操作且类型同样不可变。# 适用于 Python 3.0x [1, 2, 3]y xz x.copy() # list.copy() 需要 Python 3.3print(x is y) # True 同一个对象print(x z) # True 值相等print(x is z) # False 不是同一个对象print(id(y) id(x)) # Trueis与的区别就体现在这里问「值是否相等」is问「是不是同一个对象」。前者可被__eq__定制后者不可被覆盖。值能不能改决定了对象是可变的还是不可变的list、dict、set可变int、str、tuple、frozenset不可变。注意一个细节——不可变容器里如果装的是可变对象容器的值会跟着变但它本身仍被算作不可变因为里面引用关系没变。二、对象链条实例 → 类 → 元类 → type既然类、函数、模块也都是对象它们就有类型。这条链条是 Python 对象模型的骨架# 适用于 Python 3.0import jsondef f():passprint(type(1)) # class intprint(type(f)) # class functionprint(type(json)) # class moduleprint(type(int)) # class typeprint(type(type)) # class type ← 到这里闭环print(type(object)) # class typeprint(object.__bases__) # () ← object 没有基类print(type.__bases__) # (class object,)对象type(x)是不是对象整数1int是函数ffunction是模块jsonmodule是类inttype是type自身type是NoneNoneType是「一切数据都是对象」的意思就是这条链上每一环都能被type()问一句、都有id()、都能作为参数传递。类是对象所以能当参数传给函数、能被装饰器改写函数是对象所以能塞进列表、能挂自定义属性# 适用于 Python 3.0def f():return hif.tag 示例 # 函数也是对象可以加属性print(f.tag) # 示例三、哪些东西「不是」对象把边界划出来比一味重复口号有用关键字与运算符if、for、and、is、in是语法不是可传递的对象。语句与缩进x 1是一条语句不是对象缩进表达块结构更不是对象。变量名x只是命名空间里的一个键绑定到某个对象被绑定的是右侧那个对象不是名字本身。字面量的「源码文本」源码里写下的1是文本运行期参与运算的是它求值得到的int对象。所以写x 1时说「x 是对象」并不准确准确说法是「x 这个名字绑定到了一个 int 对象」。理解这点之后就不难解释为什么下面的行为是理所当然的# 适用于 Python 3.0a [1, 2]b ab.append(3)print(a) # [1, 2, 3] ← a 和 b 绑定的是同一个对象四、从文档反推实现C 层的对象长什么样CPython 的实现思路是每个 Python 对象在 C 层都是一个结构体结构体开头有固定的头部包含一个引用计数和一个指向类型对象的指针。引用计数降到 0 时对象被回收这就是 CPython 的主要内存管理方式它还会有循环垃圾回收来兜底。基于这套实现官方文档标明了两个「实现细节」id(x)在 CPython 里就是对象所在的内存地址这是 CPython 的实现细节换一个 Python 实现就不保证。可以用sys.getrefcount(obj)观察引用计数。但官方明确提醒返回值通常比你想的多 1因为函数参数本身是一个临时引用而且有些「不朽对象」的引用计数极高并不反映真实引用数所以除了判断 0 或 1不要依赖这个数字。# 适用于 Python 3.0import syss helloprint(sys.getrefcount(s)) # 比实际多 1仅供观察真正想读「源码」该看的是 CPython 仓库里描述对象与类型系统的部分例如Include/object.h里的对象头部定义、Objects/typeobject.c里类型对象与元类机制的实现。本机没有编译工具链也无法运行解释器这里只讲结构与结论不逐行分析源码。实战几个常被拿来验证的结论小整数缓存CPython 会缓存-5到256之间的整数对象因此这个区间内相同的小整数常常是同一个对象超出范围就不保证。这是实现细节不要依赖判等一律用# 适用于 Python 3.0a 256b 256print(a is b) # TrueCPython 小整数缓存属实现细节big1 1000big2 1000print(big1 is big2) # 不保证别用 is 比较数值可变默认参数默认值在函数定义时求值一次并被后续所有调用共享# 适用于 Python 3.0def append_to(item, target[]): # ❌ 默认值只算一次target.append(item)return targetprint(append_to(1)) # [1]print(append_to(2)) # [1, 2] ← 同一个列表被反复使用浮点数直接用比较0.1 0.2 0.3的结果是False因为二进制浮点无法精确表示这些十进制小数。比较浮点应改用容差。统一框架type与object的循环关系、类和函数的可传递性最终都落在「对象有类型、类型也是对象」这一条上把这条记住isinstance、issubclass、元类这些问题就有了统一的解释框架。常见坑点把「变量」当成对象❌x [1]; y x; y [2]然后说「改了 x」→ 实际只是把名字y重新绑定到新对象x仍是原来的列表。 ✅ 分清「名字绑定」和「对象本身」重新赋值改的是绑定原地方法如append才改对象。用is比较数值或字符串❌if x is 1000:/if name is abc:→ 结果依赖小整数缓存、常量折叠、字符串驻留都是实现细节不保证。 ✅ 一律用is只留给None、True、False这类单例。以为id()一定是内存地址❌ 依赖id()的数值做地址运算或调式假设。 ✅ 文档只保证「在对象存活期间唯一且不变」它是 CPython 的内存地址这一点属于实现细节。可变默认参数❌def f(x, lst[]): lst.append(x); return lst→ 默认列表被跨调用共享数据越积越多。 ✅def f(x, lstNone): lst [] if lst is None else lst或改用不可变默认值。把sys.getrefcount当成精确引用数❌assert sys.getrefcount(obj) 2→ 返回值通常比实际多 1临时参数引用不朽对象更是完全对不上。 ✅ 官方说除判断 0 或 1 外不要依赖它仅作观察。以为type(True) is int❌ 用type(x) is int判「是不是整数」→True是int的子类却会判为否。 ✅isinstance(True, int)为True判类型优先用isinstance。以为对不可变对象用是原地修改❌s a; t s; s b后以为t也变了 → 实际s绑到了新字符串t还是a。 ✅ 记住字符串、数字、元组的「修改」都是新建对象只有可变对象才有原地修改。把口号当规则用❌ 因为「万物皆对象」就以为if、、变量名都能传进函数。 ✅ 数据才是对象语法、运算符、名字不是。Python 2 里旧式类实例的type()结果也与新式类不同而 Python 2.7 已于 2020 年 1 月 1 日停止维护Python 3 统一为「所有类都是新式类、都是type造的实例」。总结结论是否严格说明数据都由对象表示是官方定义连代码都是对象每个对象有标识、类型、值是标识与类型不可变值可变可不变关键字/运算符/名字是对象否它们属于语法或绑定不是对象id(x)是内存地址实现细节仅 CPython且官方标明为实现细节小整数缓存、字符串驻留实现细节不要依赖判等用「万物皆对象」的正确打开方式是把它翻译成「类型本身也是对象于是一切都遵循同一套对象规则」。这句话真正的价值不在口号而在于它带来的统一性——类能当参数、函数能有属性、type与object互为前提全部由「对象有类型、类型也是对象」这一条推出来。至于具体的存储细节与引用计数属于 CPython 的实现细节理解原理即可不要写进依赖它们的代码里。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询