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

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

目录
相关文章
|
7月前
在代码优化过程中,常见的错误和bug包括以下几点
在代码优化过程中,常见的错误和bug包括以下几点
|
1月前
|
机器学习/深度学习 人工智能 程序员
大模型时代的思考:小心陷入ChatLLMs构建的蜜糖陷阱-基于人类反馈的间接(反向)驯化-你是否有注意到?
本文探讨了大模型基于人类反馈训练的原理及其潜在风险,特别是大模型在迎合用户需求时可能带来的“蜜糖陷阱”。通过实际案例分析,强调了理性使用大模型的重要性,提出了保持批判性思维、明确人机协作边界、提升人类判断力和创新能力等建议,旨在让大模型真正为人类服务,而不是限制人类思维。
|
7月前
|
算法 程序员
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
75 7
|
测试技术
代码为啥不能过度优化
代码为啥不能过度优化
81 0
关于《生成器运行时机导致的难以察觉的 bug》勘误
关于《生成器运行时机导致的难以察觉的 bug》勘误
81 0
|
存储 缓存 安全
RxJava 容易忽视的细节: subscribeOn() 方法没有按照预期地运行
RxJava 容易忽视的细节: subscribeOn() 方法没有按照预期地运行
571 0
|
机器学习/深度学习 存储 Rust
烧脑 C++ 之消除重复代码
最近偶然看到一篇 2006 年的老文章《[Tour de Babel](https://sites.google.com/site/steveyegge2/tour-de-babel)》 ([中文翻译](https://code.google.com/archive/p/windows-config/wikis/TourDeBabel.wiki)),评论各种编程语言,其中提到 C++ 有太多容易引
1657 0