一行代码,更新对iter,lambda的认知
·
md5 = hashlib.md5()
# 用二进制方式读取大文件也不会卡
with open(file_path, 'rb') as f:
# 分次读取,防止内存爆炸
for chunk in iter(lambda: f.read(4096), b''):
md5.update(chunk)
一、先讲:iter () 有两种语法形式
形式 1:普通用法
iter(可迭代对象)
比如:
iter([1,2,3])
形式 2:带两个参数的特殊语法
iter(函数, 哨兵值)
语法规则:
- 第一个参数:必须是一个无参函数,每次调用返回一个值
- 第二个参数:叫哨兵(sentinel),终止标记
- 工作逻辑:
- 循环不停调用这个无参函数
- 只要返回值 ≠ 哨兵值,就产出这个值
- 一旦返回值 == 哨兵值,立刻终止迭代,结束循环
二、第二点:lambda 可以不带任何参数
平时习惯写:
lambda x: func(x)
这是带一个形参的 lambda。
但 lambda 完全可以空括号、无参数:
lambda: f.read(4096)
关键点:
lambda后面可以不写任何变量- 冒号后面直接写表达式就行
- 作用就是:造一个不用传参、调用就返回结果的临时函数
放在 iter 里刚好适配:因为 iter(函数, 哨兵) 要求第一个参数就是无参函数。
三、第三点:b'' 是什么意思
- Python 里 带 b 前缀 = 字节串(bytes)
''是空字符串,b''就是空字节串- 文件二进制读取时:
f.read(4096)读到有内容:返回b'xxxx'- 文件读到末尾,没东西可读了:固定返回
b''
所以:b'' 就是 文件读完的终止信号。
四、把整句拼起来逐行拆解
iter(lambda: f.read(4096), b'')
拆解翻译:
-
lambda: f.read(4096)造一个无参函数:一调用,就从文件读 4096 字节 -
b''设定哨兵:如果读到空字节串,就停止 -
iter(无参函数, 哨兵)反复调用读文件函数,每次返回一块数据;一旦读到b'',马上停。
然后 for chunk in ... 就是一块一块遍历读取的内容。
五、等价写成熟悉的 while 版本,彻底对照
# 优雅简写版
for chunk in iter(lambda: f.read(4096), b''):
md5.update(chunk)
等价老式写法:
while True:
chunk = f.read(4096)
if chunk == b'': # 碰到哨兵,退出
break
md5.update(chunk)
完全一模一样的逻辑,只是用 iter 语法做了精简。
测试一下理解得对不对:
aa = [1,2,3]
for bb in iter(lambda:aa.pop(0), 3):
print(bb)
输出结果是:

六、总结三个新认知
iter(函数, 哨兵):反复调用无参函数,等于返回哨兵就停;lambda:可以无参数,直接写后续表达式,适合临时做无参回调;b''是二进制文件读到末尾的空字节标记,作为循环终止条件。
更多推荐

所有评论(0)