① Memory & Types

可变 vs 不可变

  • 不可变:int / str / tuple → 可作 dict key
  • 可变:list / dict / set → 不能作 dict key

is vs ==

  • is → 同一个对象;== → 值相等
  • a = [1,2]; b = [1,2]a == ba is not b

深/浅拷贝

  • 浅拷贝 copy.copy():嵌套对象仍是引用
  • 深拷贝 copy.deepcopy():完全独立的副本

⚠️ 经典陷阱:def f(x=[]) 默认参数只创建一次,所有调用共享!
正确写法:def f(x=None): x = x or []


② Data Structures

类型特点
list增删末尾 O(1),pop(0) / insert 是 O(n)
dict查找/插入/删除 O(1),Python 3.7+ 有序
set成员判断 O(1),元素必须可哈希
tuple不可变 list,可作 dict key

怎么选:

  • 需要快速查找 → dict / set
  • 需要头尾操作 → collections.deque
  • 需要优先队列 → heapq(最小堆)
  • 计数 → Counter;自动默认值 → defaultdict

排序:sort() / sorted() 都是 Timsort,稳定,O(n log n)


③ Functions

装饰器

  • 本质:@decfunc = dec(func),是语法糖
  • 用途:日志、计时、权限校验、缓存
  • ⚠️ 要用 @functools.wraps(func) 保留原函数名

生成器

  • yield 代替 return,惰性求值,省内存
  • 大数据优先用 (x for x in ...) 而非 [x for x in ...]

常用内置

  • map / filter / zip / enumerate
  • lambda:匿名函数,适合简单场景
  • *args(tuple)/ **kwargs(dict):可变参数

④ OOP & Classes

三大特性:封装 / 继承 / 多态

常考区别:

  • @classmethod → 第一个参数是 cls,可访问类,常用于工厂方法
  • @staticmethod → 普通函数,放在类里只是归类,不能访问类或实例
  • @property → 把方法当属性用,可加 setter 做数据验证

继承与 MRO:

  • 多继承时方法查找顺序:ClassName.__mro__
  • super() 调用父类方法

__str__ vs __repr__

  • __str__print() 显示,给用户看
  • __repr__ → 调试用,应能还原对象

⑤ GIL & Concurrency

GIL 是什么
CPython 的全局锁,同一时刻只有一个线程跑 Python 代码。
原因:内存管理(引用计数)不是线程安全的。

核心结论:

  • I/O 密集(网络请求、文件读写)→ 用 threading
  • CPU 密集(大量计算)→ 用 multiprocessing

asyncio:
async/await 写法,单线程处理大量 I/O 并发,适合高并发网络场景。
⚠️ 不能有任何阻塞调用(否则会卡死整个事件循环)


⑥ Common Pitfalls

循环闭包

funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])  # [2, 2, 2] ← 全是 2!
# 正确:
funcs = [lambda i=i: i for i in range(3)]

字符串拼接

# 慢,O(n²)
s = ""
for word in words:
    s += word
 
# 快
s = "".join(words)

None 判断

if x is None:   # ✅
if x == None:   # ❌

列表推导式 vs 循环
推导式在 C 层面执行,比等价的 for 循环快 30-50%,优先使用。

with 语句
上下文管理器,自动处理资源的释放(文件关闭、锁释放等)。