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

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

目录
相关文章
|
3月前
在代码优化过程中,常见的错误和bug包括以下几点
在代码优化过程中,常见的错误和bug包括以下几点
|
5天前
|
Cloud Native 数据处理
项目环境测试问题之当异步任务在运行过程中抛出非预期的异常会导致后果如何解决
项目环境测试问题之当异步任务在运行过程中抛出非预期的异常会导致后果如何解决
|
1月前
|
敏捷开发 测试技术 持续交付
编码过程中有效地管理时间和精力,避免陷入无休止的调试循环
编码过程中有效地管理时间和精力,避免陷入无休止的调试循环
|
3月前
|
算法 程序员
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
为何程序员在编写程序时难以一次性将所有代码完美无瑕地完成,而是需要经历反复修改Bug的过程?
48 7
|
10月前
|
存储 自然语言处理 算法
通过实际的例子,介绍编译器的工作过程
通过实际的例子,介绍编译器的工作过程
关于《生成器运行时机导致的难以察觉的 bug》勘误
关于《生成器运行时机导致的难以察觉的 bug》勘误
64 0
|
存储 缓存 安全
RxJava 容易忽视的细节: subscribeOn() 方法没有按照预期地运行
RxJava 容易忽视的细节: subscribeOn() 方法没有按照预期地运行
534 0
|
监控 测试技术
消灭bug秘籍 如何处理大型软件中的错误和异常
"我在测试中没有发现任何bug,这就意味着没有bug……对吗?"千万不要这样认为。由于大型软件的复杂程度很高,不管你做了多少测试,都不可能达到零bug的程度。因为你并不能揣测出用户的所有使用方式,因此,了解应用程序中错误和异常之间的差异,是非常重要的。
1240 0