对象、拷贝与异常
名字与对象
python
a = [1, 2]
b = a
b.append(3)
print(a) # [1, 2, 3]赋值绑定名字,不复制对象。id 表示对象身份;是否可变决定能否通过某个引用观察到原地变化。
python
a = a + [4] # 创建新 List 并重新绑定
a += [4] # List 通常原地扩展+= 调用就地运算协议;不可变对象无法原地改变,因此会生成新对象。不要仅凭运算符外观推断是否修改原对象。
浅拷贝与深拷贝
python
from copy import copy, deepcopy
outer = [[1], [2]]
shallow = copy(outer)
deep = deepcopy(outer)- 浅拷贝创建新外层容器,内部元素仍是相同引用。
- 深拷贝递归复制对象图,并用 Memo 处理循环引用和共享关系。
- 深拷贝不一定合理:数据库连接、锁、文件、缓存和领域实体可能不应复制。
equality 与 identity
== 调用值相等协议,is 比较身份:
python
value is None
type(value) is int
isinstance(value, int)一般类型判断使用 isinstance,它支持继承和抽象基类。严格排除 bool 时要注意 bool 是 int 的子类。
hash 与可变性
Dict Key 与 Set 元素必须 Hashable,并且对象相等时 Hash 必须相同。List、Dict、Set 因可变而不能作为 Key;Tuple 只有所有元素都 Hashable 时才可 Hash。
自定义类实现 __eq__ 后通常需要同步考虑 __hash__。把参与 Hash 的字段设为可变会使对象加入 Set 后无法再正确定位。
try、else 与 finally
python
try:
result = parse(raw)
except ValueError as exc:
handle(exc)
else:
persist(result)
finally:
release()else只在try没有抛异常时执行,可缩小except意外捕获范围。finally无论正常、异常还是return都会执行。- 在
finally中return会覆盖原返回值或正在传播的异常,应避免。 except Exception不捕获KeyboardInterrupt、SystemExit等BaseException子类。
异常转换使用 raise NewError(...) from exc 保留因果链;明确隐藏上下文才使用 from None。
with 与上下文管理器
python
with open(path, encoding="utf-8") as stream:
content = stream.read()with 确保 __exit__ 在离开代码块时执行。__exit__ 返回真值会抑制异常,编写自定义 Context Manager 时不要无意吞掉错误。
多个资源可写在一个 with 中;动态数量的资源使用 contextlib.ExitStack。异步资源使用 async with,不能用同步 Context Manager 假装完成异步关闭。