生成器运行时机导致的难以察觉的 bug

简介: 生成器运行时机导致的难以察觉的 bug

摄影:产品经理比起法餐,我还是更喜欢烧烤和火锅粉

我们知道,生成器函数初始化的时候,它返回的是一个生成器。里面的代码一开始是没有运行的。只有当这个生成器被迭代的时候,才会运行:

正是由于这个原理,如果没有理解就贸然使用,可能会产生你难以理解的 bug。我们来看一个例子:

def do_filter(datas, to_filter):    for data in datas:        if to_filter in data:            continue        yield data
def trash_filter():    datas = ['有效信息', '重要信息', '隐私信息', '脏数据', '保密信息', '无效数据', '大数据']    result = do_filter(datas, '无效')    result = do_filter(result, '脏')    return result
for data in trash_filter():    print(data)

在这段代码里面,我们有两个生成器,它们分别过滤无效

我们再来看第二段代码:


def do_filter(datas, to_filter):    for data in datas:        if to_filter in data:            continue        yield data
def trash_filter():    datas = ['有效信息', '重要信息', '隐私信息', '脏数据', '保密信息', '无效数据', '大数据']    for word in ['无效', '脏']:        result = do_filter(datas, word)    return result
for data in trash_filter():    print(data)

运行效果如下图所示:

可以看到,在这段代码只是把原来的分两次调用改成了使用 for 循环,但是却发现过滤出问题了,无效数据没有被正确过滤。

要解释这个问题的原因,我们还要从生成器的延迟执行说起。回到最开始的代码,我们修改一下,增加一个外部变量:


outer = 123
def i_am_generator():    print('生成器函数运行了。外部变量的值为:', outer)    yield
generator = i_am_generator()print(f'现在返回的是一个生成器对象:{generator}')
outer = 456for _ in generator:    ...

运行效果如下图所示:

一开始外部变量outer的值为123,然后我执行生成器函数,创建一个生成器。然后修改外部变量的值为456.最后再对生成器进行迭代。可以看到,迭代生成器的时候,生成器内部的代码才会真正去读这个外部变量。而它读的时候,外部变量已经被改成了456。

所以,对于代码:



for word in ['无效', '脏']:        result = do_filter(datas, word)

第一次循环 word 的值确实取到了无效,但是result = do_filter(datas, word)只是返回了一个生成器,这个生成器没有执行,所以它没有读取 word 变量里面的值。第二次循环,word 变量的值变成了,此时第二次生成了新的生成器。

最后返回的是第二个生成器。当我们对第二个生成器进行迭代的时候,它才真正读取了这个值。

所以,上面这段代码与下面这段代码是等效的:



result = do_filter(datas, '脏')result = do_filter(datas, '脏')

所以只会过滤包含字的内容,却不会过滤包含无效的内容。

目录
相关文章
|
11月前
|
安全 物联网
物联网卡不能更换设备使用吗
物联网卡(IoT SIM卡)是否允许更换设备使用,这主要取决于物联网服务提供商的具体政策和服务条款。通常,物联网卡是为特定设备或应用场景设计的,因此一些服务提供商会限制卡的更换使用,主要是出于安全、管理、网络优化和避免滥用等考虑
|
11月前
|
传感器 监控 数据可视化
数字孪生技术:工业4.0的关键要素
【10月更文挑战第3天】数字孪生技术是工业4.0的关键要素,通过将物理实体与虚拟模型映射,实现数据收集、分析和实时监控,优化生产和管理流程。本文详细介绍了数字孪生技术的基本原理、应用场景及其在制造业、能源、建筑、医疗和农业领域的具体应用,展示了其在提高生产效率、增强产品质量、降低运营成本和提升创新能力方面的显著优势,揭示了其对工业4.0发展的深远影响。
ECharts 饼图切换数据源bug 开始没数据显示 切换或刷新后显示
ECharts 饼图切换数据源bug 开始没数据显示 切换或刷新后显示
311 0
|
SQL 数据库 索引
SQL 编程最佳实践简直太牛啦!带你编写高效又可维护的 SQL 代码,轻松应对数据库挑战!
【8月更文挑战第31天】在SQL编程中,高效与可维护的代码至关重要,不仅能提升数据库性能,还降低维护成本。本文通过案例分析探讨SQL最佳实践:避免全表扫描,利用索引加速查询;合理使用JOIN,避免性能问题;避免使用`SELECT *`,减少不必要的数据传输;使用`COMMIT`和`ROLLBACK`确保事务一致性;添加注释提高代码可读性。遵循这些实践,不仅提升性能,还便于后期维护和扩展。应根据具体情况选择合适方法并持续优化SQL代码。
206 0
|
存储 Ubuntu Linux
Docker容器简介、优缺点与安装
Docker容器简介、优缺点与安装
|
资源调度 数据可视化
用二元泊松模型预测2022年世界杯淘汰赛结果
双泊松模型有一个严重的缺陷,那就是它假设比赛中两队的比分是条件独立的。而我们都知道,在对抗性比赛中,两队的比分是存在关联的,双泊松模型可以描述比分的这种关联性,提高了比赛结果预测的准确度。
776 1
用二元泊松模型预测2022年世界杯淘汰赛结果
|
存储 运维 JavaScript
云HIS是什么?HIS系统为什么要上云?云HIS有哪些优点?
云HIS的主要功能作用是提供四个面向的服务,即面向居民的健康服务、面向医疗机构的医疗服务、面向各级管理机关的卫生管理服务、面向其它卫生机构的卫生协同服务。
1022 1
|
人工智能 并行计算 计算机视觉
|
小程序 JavaScript 定位技术
微信小程序地图实现标记多个位置
微信小程序地图实现标记多个位置
558 0
|
负载均衡 网络协议 JavaScript
一个注解实现 WebSocket 集群方案,这样玩才爽! 上
一个注解实现 WebSocket 集群方案,这样玩才爽! 上