Python 核心 · #11 / 11
Python 核心(进阶)
迭代器、生成器、异常、文件、模块
为什么重要
这是让 Python 在大规模场景下保持高效的真实世界工具箱。
核心思想
可迭代对象让你惰性地流式处理数据(适合超大 / 无限的序列)。生成器是编写迭代器最廉价的方式。异常在不四处散布错误检查的情况下报告失败。上下文管理器(with)保证清理工作一定会完成。
试一试
用 yield 的生成器——惰性地产出值:
def fib():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
g = fib()
first_ten = [next(g) for _ in range(10)]
print(first_ten)
生成器表达式与列表推导式——语法相同,但前者是惰性求值:
# Total memory: O(1) for the generator, O(n) for the list
nums = range(1_000_000)
total = sum(x * x for x in nums if x % 3 == 0)
print("sum of squares of multiples of 3:", total)
异常 + try/except/else/finally:
def safe_div(a, b):
try:
result = a / b
except ZeroDivisionError:
return None
except TypeError as e:
return f"type error: {e}"
else:
return result
finally:
# runs no matter what — log, close files, etc.
pass
print(safe_div(10, 2))
print(safe_div(10, 0))
print(safe_div(10, "x"))
标准库必备
你很少需要从零开始编写数据结构——标准库已经提供了快速的版本:
collections:deque、defaultdict、Counteritertools:accumulate、product、permutationsmath、statistics、random
类型注解 + 数据类(dataclass)
类型注解记录意图(并为编辑器 / 类型检查器提供支持);@dataclass 帮你写好样板式的 __init__ / __repr__:
from dataclasses import dataclass
def add(a: int, b: int) -> int:
return a + b
@dataclass
class Point:
x: int
y: int
快速检查
- 问: 为什么要用
with open(...)? 答: 它会自动关闭文件。
小练习
- 写一个产出偶数的生成器。
- 安全地捕获一个
KeyError。 - 读取一个文件并统计它的行数。
该做与不该做
- 该做:对大型数据流使用生成器。
- 该做:捕获具体的异常。
- 不该做:让文件一直开着。
- 不该做:默默地吞掉异常。
深入一点——自定义迭代
任何实现了 __iter__(返回迭代器)和 __next__(产出下一个值或抛出 StopIteration)的对象,都能在 for 循环中使用:
class CounterIter:
def __init__(self, n):
self.n = n
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i >= self.n:
raise StopIteration
val = self.i
self.i += 1
return val常见错误
- 错误: 到处使用裸
except:。 修正: 捕获具体的错误。 - 错误: 在生成器里忘了
yield。 修正: 用yield来流式产出值。 - 错误: 用
read()读取超大文件。 修正: 逐行迭代。
关键要点
- 生成器(
yield)以恒定内存构建迭代器。 - 对大型输入,使用生成器表达式
sum(x*x for x in nums)而非sum([x*x for x in nums])。 - 对预期内的失败用
try/except来控制流程;让意料之外的错误向上冒泡。 with open(path) as f:是正确的惯用法——f.close()一定会被执行。collections/itertools为你提供快速、久经考验的构建模块。