生成器高级用法

举报
brucexiaogui 发表于 2022/08/28 22:04:46 2022/08/28
【摘要】 生成器高级用法 1.概述 这篇文章介绍生成器的一些使用技巧,同时用它来替代传统容器实现一些好用的功能。 2.生成器 2.1.生成器介绍 生成器是python里的一种特殊的数据类型,他是一个不断给...

生成器高级用法

1.概述

这篇文章介绍生成器的一些使用技巧,同时用它来替代传统容器实现一些好用的功能。

2.生成器

2.1.生成器介绍

生成器是python里的一种特殊的数据类型,他是一个不断给调用方生成内容的类型。定义一个生成器需要用到生成器函数与yield关键字。

1.创建一个生成器Demo

# 生成器
def generate_even(max_number):
	# 一个简单的生成器,返回0到max_number之间所有的偶数
    for i in range(0, max_number):
        if i % 2 == 0:
            yield i

# 遍历生成器对象,输出结果
for i in generate_even(100):
    print(i)

# 调用next()函数可以逐步从生成器里拿到结果
g = generate_even(10)
print(next(g))
print(next(g))
print(next(g))

# 因为生成器是可迭代对象,所以可以使用容器内置函数将其转为其他容器类型。例如将它转为list容器
mylist = list(generate_even(10))
print(f'将生成器转换为list容器:type({mylist})'

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

2.2.按需返回替代容器

在Python2时代,如果用range()生成一个非常大的数字序列,速度会非常慢。这是因为range()需要组装并返回一个巨大的列表。整个计算与内存分配会耗费大量时间。

# 在python2中的range()会将结果组装的一个列表,一次性返回所有数字。
>>> range(4)
[0, 1, 2, 3]

  
 
  • 1
  • 2
  • 3

在python3时代,调用range()瞬间就会返回结果,因为它不在返回列表,而是返回一个类型为range的惰性计算对象。
当序列过大时,新的range()函数不再会一次性耗费大量内存和时间,生成一个巨大的列表,而是仅在迭代时按需返回数字。
range()的进化虽然简单,但它代表了一个重要的编程思维——按需生成,而不是一次性返回

虽然都是返回结果,但yield和return的最大不同之处在于,return的返回是一次性的,使用它会直接终止整个函数执行。而yield可以逐步给调用方生成结果。

# r 是range对象,而非装满数字的列表
>>> r = range(10000000)
# 只有在迭代range对象时,他才会不断生成新的数字
>>> for i in r:
>>> 	print(i)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

3.生成器应用案例

3.1.用生成器替代列表

在写代码过程中,我们经常要处理一些数据,假如在批处理时数据量过大或者处理逻辑复杂导致处理速度很慢,例如下面的示例存在两点问题:

  • 将处理后的大数据放到列表中,一次性返回占用很大的内存,同时处理速度也很慢。
  • 如果函数调用方想在满足特定条件时中断,不在继续处理后面的数据,现在batch_process函数是做不到的。
def batch_process(items):
    '''
    批量多个items对象
    :param items:
    :return:
    '''
    result = []
    for item in range(0, items):
        # 假如处理item需要花费大量时间
        if item % 2 == 0:
            result.append(item)
    # 处理的结果拼接到列表中返回
    return result
    
process = batch_process(10)
print(process)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

为了解决上面的问题,我们可以使用生成器改写它,用yield替代列表。

def batch_yield(items):
    '''
        批量多个items对象
        :param items:
        :return:
    '''
    for item in range(0, items):
        # 假如处理item需要花费大量时间
        if item % 2 == 0:
            yield item


for i in batch_yield(10):
    # 满足特定条件后不在处理后面的数据
    if i == 4:
        break
    print(i)

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

文章来源: brucelong.blog.csdn.net,作者:Bruce小鬼,版权归原作者所有,如需转载,请联系作者。

原文链接:brucelong.blog.csdn.net/article/details/126567213

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。