Skip to content

Python★

可变/不可变、引用与赋值、深浅拷贝、== vs is。

Updated View as Markdown
For humans

Python 基础与对象模型

Python 的一切都是对象,理解对象模型是后续所有内容的地基。面试主线三个问题:变量是什么、可变不可变怎么分、拷贝怎么用。

对象三要素

每个对象都有三个属性:id(身份)、type(类型)、value(值)

a = [1, 2, 3]
b = a          # b 和 a 指向同一个对象
a.append(4)
print(b)       # [1, 2, 3, 4]  b 跟着变

变量是名字,不是盒子。赋值只是把名字绑定到对象上,不复制任何东西。这是 Python 和 C/Java 心智模型的核心差异。

== 与 is

比较 比什么 什么时候用
== 值相等(调用 __eq__ 业务比较,绝大多数场景
is 身份相等(id 相同) 与 None 比较、单例比较
a = [1, 2]
b = [1, 2]
a == b   # True  值相同
a is b   # False 不同对象

坑:小整数缓存(-5 到 256)和短字符串可能复用对象,is 恰好为 True,这是实现细节,别依赖。

可变与不可变

类别 类型 特点
不可变 int、float、str、tuple、frozenset 值不能改,改了就是新对象(重新绑定)
可变 list、dict、set 原地修改,id 不变

关键推论:

  • 不可变对象可哈希,能当 dict 的 key、set 的元素;list/dict 不行
  • += 对不可变对象是重新绑定(新对象),对 list 是原地修改。a += ba = a + b 对 list 行为相同但 id 可能不同(__iadd__
  • 函数默认参数用可变对象是经典坑(见函数篇)

深浅拷贝

浅拷贝共享内层, 深拷贝全部分离

  • 浅拷贝 copy.copy:新对象,但内层可变对象仍共享。改内层会影响两边
  • 深拷贝 copy.deepcopy:递归复制所有层,完全独立。代价是慢、可能递归爆栈
  • 切片 lst[:]list(lst)dict.copy() 都是浅拷贝
  • 自定义对象可定义 __copy__/__deepcopy__ 控制行为

面试追问

  1. 变量赋值是复制吗? 不是。变量是绑定到对象的名字,赋值只绑名字,对象共享
  2. 为什么 tuple 可以当 dict 的 key? 不可变所以可哈希。含 list 的 tuple 不可哈希(list 可变)
  3. == 和 is 的区别? == 比值(eq),is 比身份(id)。判 None 用 is
  4. 浅拷贝和深拷贝的区别? 浅拷贝复制外层共享内层,深拷贝递归全复制。业务上小心共享内层被意外修改
  5. 函数参数是值传递还是引用传递? 传对象引用。不可变对象改了不生效(重新绑定),可变对象改了生效(原地修改)
Navigation

Type to search…

↑↓ navigate↵ selectEsc close