生成器的引入讲解

比较一下列表生成式和生成器:
对于列表生成式而言:它在执行完毕以后,直接将所有数据全部加载到内存中。列表生成器可以遍历多次里面的所有元素!
                    优点:由于所有数据已经存在内存,检索效率变高
                    缺点:如果一些数据不经被常使用,会存在内存的浪费
对于生成器而言:它执行完毕以后,仅仅返回的是一个generator对象,内存中并不存在generator中的元素值,生成器里的元素当操作者要要一个元素就next一次,生成器里的元素只能遍历一次,当元素第一次全部取完就无法再从生成器中获取
                     优点:内存得到很好的利用,不会浪费
                     缺点:相对的效率变低了
创建生成器对象(两种生成器的创建)
方式一:生成器表达式
genn = (x * 2 for x in range(1, 11))
# print(type(genn))      # 查看genn的类型!<class 'generator'> 内存里记入的是一个generator对象 元素没有加载在内存!
# 遍历循环打印genn中的所有元素
for i in genn:
    print(i)
print()# 空一行
for i in genn:  # 想再打印一次genn中的所有元素
    print(i)    #结果此行代码不被执行,因为生成器中的所有元素只能被遍历一次。
print(next(genn))  # 报错! 因为生成器中的元素已经被全部遍历打印出来,不能再循环遍历,print(next(genn))因为强行打印下一个元素,所以报错! 说明: 生成器对象是不可逆的!获取生成器里面的元素仅仅只能获取一次(好好理解这句话)
list = list(genn)  # 想要括号里面的类型变成列表,用list去接受一下
print(list) # 打印list  将生成器里的元素以列表的形式打印出来:[2, 4, 6, 8, 10, 12, 14, 16, 18, 20] 所有的内容加载在内存了

# 遍历list
 for i in list:
     print(i)

# print('*' * 50)  # 在输出台区别上一行打印  用 50个*  隔开
#
# for i in list:  # 打印完*号,再遍历一次
#     print(i)
# 对于list而言 想遍历多少次遍历多少次 里面的元素可以无限循环获取,这个也是list和generetor内部的一些不同点
# 方式二: 生成器函数
# 使用函数来创建生成式
def func(n):  # 有形参的
    for i in range(n):
        yield i         # 这个函数就结束了,其实它也不算有返回值的函数
# 当执行func函数时,for会被启动,假如n=5,for循环0-4,走完for语句,然后就有yield,当你要一个值的时候,yiled给你一个值,
# 然后挂起,(计入函数的形式状态),等你再去执行这个函数的时候,它就从下一个点,再yield一个给你。
f = func(5) # func 传一个5,可以得到一个f对象,f对象就是方法对象
print(f)  # 打印f,运行结果为:<generator object func at 0x0000027E52574A98> # 是一个generator对象  得到的是func一个generator的完整的对象,并不是里面有数据的, 那你要它里面的数据能够拿到,就要给它执行起来!
print(next(f)) # 执行f ,next(next:下一个) 是在生成器中一次取一个,
# next 一下 ,就是我对这个generator对象往下走一次,走完yield i 就标注一下,然后我在next一下,yield就在标注的地方再往下走
print(next(f))
print(next(f))
print(next(f))
print(next(f))
# print(next(f))  # 这个next已经超出了range的范围,报一个异常,
阅读更多

没有更多推荐了,返回首页