# Python 陷阱 本章汇总 Python 开发中最常见的陷阱和易错点,帮助你避免踩坑。 ```{toctree} :maxdepth: 2 common_mistakes performance memory debugging ``` ## 陷阱分类 ::::{grid} 2 :gutter: 2 :::{grid-item-card} 🐛 常见错误 可变默认参数、作用域问题、浮点数精度、字符串编码等。 ::: :::{grid-item-card} ⚡ 性能陷阱 低效循环、不当数据结构选择、内存复制、过早优化等。 ::: :::{grid-item-card} 💾 内存问题 循环引用、大对象处理、生成器误用、缓存泄漏等。 ::: :::{grid-item-card} 🔍 调试技巧 日志最佳实践、性能分析、内存分析、常用工具等。 ::: :::: ## 快速参考:Top 10 陷阱 ### 1. 可变默认参数 ```python # ❌ 错误 def append_to(item, lst=[]): lst.append(item) return lst print(append_to(1)) # [1] print(append_to(2)) # [1, 2] 不是 [2]! # ✅ 正确 def append_to(item, lst=None): if lst is None: lst = [] lst.append(item) return lst ``` ### 2. 循环中的闭包 ```python # ❌ 错误 funcs = [lambda: i for i in range(3)] print([f() for f in funcs]) # [2, 2, 2] # ✅ 正确 funcs = [lambda i=i: i for i in range(3)] print([f() for f in funcs]) # [0, 1, 2] ``` ### 3. is vs == ```python # ❌ 错误 a = 256 b = 256 print(a is b) # True (小整数缓存) a = 257 b = 257 print(a is b) # False! # ✅ 正确:用 == 比较值 print(a == b) # True # is 只用于 None 比较 if x is None: pass ``` ### 4. 修改迭代中的列表 ```python # ❌ 错误 items = [1, 2, 3, 4, 5] for item in items: if item % 2 == 0: items.remove(item) # 跳过元素! print(items) # [1, 3, 5] 可能不是预期 # ✅ 正确 items = [1, 2, 3, 4, 5] items = [x for x in items if x % 2 != 0] ``` ### 5. 字典迭代时修改 ```python # ❌ 错误 d = {'a': 1, 'b': 2, 'c': 3} for k in d: if d[k] == 2: del d[k] # RuntimeError! # ✅ 正确 d = {k: v for k, v in d.items() if v != 2} # 或 for k in list(d.keys()): # 复制 keys if d[k] == 2: del d[k] ``` ### 6. 浮点数比较 ```python # ❌ 错误 print(0.1 + 0.2 == 0.3) # False! # ✅ 正确 import math print(math.isclose(0.1 + 0.2, 0.3)) # True # 或使用 decimal from decimal import Decimal print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3')) # True ``` ### 7. 类属性共享 ```python # ❌ 错误 class Student: grades = [] # 类属性 def add_grade(self, grade): self.grades.append(grade) s1 = Student() s2 = Student() s1.add_grade(90) print(s2.grades) # [90] 被共享了! # ✅ 正确 class Student: def __init__(self): self.grades = [] # 实例属性 ``` ### 8. 异常中的 return ```python # ⚠️ 容易混淆 def confusing(): try: return "try" finally: return "finally" # finally 的 return 覆盖 try 的! print(confusing()) # "finally" # ✅ 最佳实践:finally 中不要 return def clear(): try: return "try" finally: # 只做清理,不要 return pass ``` ### 9. GIL 与线程 ```python # ⚠️ CPU 密集型任务,多线程不会更快 import threading counter = 0 def increment(): global counter for _ in range(1000000): counter += 1 # 不是原子操作! threads = [threading.Thread(target=increment) for _ in range(2)] for t in threads: t.start() for t in threads: t.join() print(counter) # 小于 2000000! # ✅ CPU 密集型用多进程 from multiprocessing import Pool, Value ``` ### 10. 作用域陷阱 ```python # ❌ 错误 x = 10 def foo(): print(x) # UnboundLocalError! x = 20 # ✅ 正确 def foo(): global x # 或 nonlocal(嵌套函数) print(x) x = 20 # 或者不修改全局变量(推荐) def foo(x): return x + 10 ``` ## 调试快速参考 ```python # 1. 打印变量和类型 print(f"{var=}, {type(var)=}") # 2. 使用断点 breakpoint() # Python 3.7+ # 3. 追踪函数调用 import traceback traceback.print_stack() # 4. 检查对象 import inspect print(inspect.getmembers(obj)) # 5. 内存使用 import sys print(sys.getsizeof(obj)) ``` ## 性能检查快速参考 ```python # 1. 时间测量 import time start = time.perf_counter() # ... 代码 ... print(f"Took {time.perf_counter() - start:.4f}s") # 2. 使用 timeit import timeit print(timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)) # 3. cProfile import cProfile cProfile.run('my_function()') # 4. 内存分析 # pip install memory_profiler # @profile # def my_function(): ... # python -m memory_profiler script.py ```