生成器运行时机导致的难以察觉的 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, '脏')

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

目录
相关文章
|
6月前
在代码优化过程中,常见的错误和bug包括以下几点
在代码优化过程中,常见的错误和bug包括以下几点
|
16天前
|
机器学习/深度学习 人工智能 程序员
大模型时代的思考:小心陷入ChatLLMs构建的蜜糖陷阱-基于人类反馈的间接(反向)驯化-你是否有注意到?
本文探讨了大模型基于人类反馈训练的原理及其潜在风险,特别是大模型在迎合用户需求时可能带来的“蜜糖陷阱”。通过实际案例分析,强调了理性使用大模型的重要性,提出了保持批判性思维、明确人机协作边界、提升人类判断力和创新能力等建议,旨在让大模型真正为人类服务,而不是限制人类思维。
|
3月前
|
Cloud Native 数据处理
项目环境测试问题之当异步任务在运行过程中抛出非预期的异常会导致后果如何解决
项目环境测试问题之当异步任务在运行过程中抛出非预期的异常会导致后果如何解决
|
4月前
|
存储
代码优化设计问题之当方法体只有一行时,独立存在的方法的必要性开始存疑问题如何解决
代码优化设计问题之当方法体只有一行时,独立存在的方法的必要性开始存疑问题如何解决
|
4月前
|
敏捷开发 测试技术 持续交付
编码过程中有效地管理时间和精力,避免陷入无休止的调试循环
编码过程中有效地管理时间和精力,避免陷入无休止的调试循环
|
5月前
|
算法 前端开发 Java
Bug复盘:接口异步返回的重要性
Bug复盘:接口异步返回的重要性
|
6月前
|
算法 程序员
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
65 7
|
6月前
|
监控 安全
线程死循环是多线程应用程序开发过程中一个难以忽视的问题,它源于线程在执行过程中因逻辑错误或不可预见的竞争状态而陷入永久运行的状态,严重影响系统的稳定性和资源利用率。那么,如何精准定位并妥善处理线程死循环现象,并在编码阶段就规避潜在风险呢?谈谈你的看法~
避免线程死循环的关键策略包括使用同步机制(如锁和信号量)、减少共享可变状态、设置超时、利用监控工具、定期代码审查和测试、异常处理及设计简洁线程逻辑。通过这些方法,可降低竞态条件、死锁风险,提升程序稳定性和可靠性。
99 0
|
测试技术
代码为啥不能过度优化
代码为啥不能过度优化
74 0
关于《生成器运行时机导致的难以察觉的 bug》勘误
关于《生成器运行时机导致的难以察觉的 bug》勘误
76 0