# review python by zzk
# From https://www.cnblogs.com/Eva-J/p/7277026.html
# and my point
# 字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的
# 可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代
# 可以被迭代要满足的要求就叫做可迭代协议。可迭代协议的定义非常简单,就是内部实现了__iter__方法
# print(dir([1,2]))
# ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
# 可以看到里面实现了__iter__ 方法,在第三行
# print([1,2].__iter__())
#
# 结果
# <list_iterator object at 0x1024784a8>
# '''
# dir([1,2].__iter__())是列表迭代器中实现的所有方法,dir([1,2])是列表中实现的所有方法,都是以列表的形式返回给我们的,
# 为了看的更清楚,我们分别把他们转换成集合,
# 然后取差集。
# '''
# #print(dir([1,2].__iter__()))
# #print(dir([1,2]))
# print(set(dir([1,2].__iter__()))-set(dir([1,2])))
#
# 结果:
# {'__length_hint__', '__next__', '__setstate__'}
# iter_l = [1,2,3,4,5,6].__iter__()
# #获取迭代器中元素的长度
# print(iter_l.__length_hint__())
# #根据索引值指定从哪里开始迭代
# print('*',iter_l.__setstate__(4))
# #一个一个的取值
# print('**',iter_l.__next__())
# print('***',iter_l.__next__())
# 在for循环中,就是在内部调用了__next__方法才能取到一个一个的值。
# 用迭代器的next方法来写一个不依赖for的遍历
# l = [1,2,3,4]
# l_iter = l.__iter__()
# print(l_iter) # <list_iterator object at 0x10b47f588>
# print(type(l_iter)) # <class 'list_iterator'>
# while True:
# try:
# item = l_iter.__next__()
# print(item)
# except StopIteration:
# break
# 迭代器遵循迭代器协议:必须拥有__iter__方法和__next__方法。
# for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,
# 先调用对象的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,
# 这样所有的对象就都可以通过for循环来遍历了,而且你看到的效果也确实如此,这就是无所不能的for循环
# 迭代器有两种:一种是调用方法直接返回的,一种是可迭代对象通过执行iter方法得到的,迭代器有的好处是可以节省内存。
# 如果在某些情况下,我们也需要节省内存,就只能自己写。我们自己写的这个能实现迭代器功能的东西就叫生成器
# Python中提供的生成器:
# 1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。
# yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
# 2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表
# 生成器Generator:
# 本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现)
# 特点:惰性运算,开发者自定义
# 初识生成器函数
# import time
# def genrator_fun1():
# a = 1
# print('现在定义了a变量')
# yield a
# b = 2
# print('现在又定义了b变量')
# yield b
#
# g1 = genrator_fun1() # 定义g1为一个生成器
# print('g1 : ',g1) # 打印g1可以发现g1就是一个生成器
# print('-'*20) # 我是华丽的分割线
# print(next(g1))
# time.sleep(1) # sleep看清执行过程
# print(next(g1))
#初识生成器二
# def produce():
# """生产衣服"""
# for i in range(2000000):
# yield "生产了第{}件衣服".format(i)
#
# product_g = produce()
# print(product_g.__next__()) #要一件衣服
# print(product_g.__next__()) #再要一件衣服
# print(product_g.__next__()) #再要一件衣服
# num = 0
# for i in product_g: # 这里迭代这个生成器,要一批衣服,比如5件
# print(i)
# num +=1
# if num == 5:
# break
#到这里我们找工厂拿了8件衣服,我一共让我的生产函数(也就是produce生成器函数)生产2000000件衣服。
#剩下的还有很多衣服,我们可以一直拿,也可以放着等想拿的时候再拿
# send
# def generator():
# print(123)
# content = yield 1
# print('=======',content)
# print(456)
# yield 2
#
# g = generator()
# print('---'*13)
# ret = g.__next__()
# print('***',ret)
# ret = g.send('hello') #send的效果和next一样
# print('***',ret)
#send 获取下一个值的效果和next基本一致
#只是在获取下一个值的时候,给上一yield的位置传递一个数据
#使用send的注意事项
# 第一次使用生成器的时候 是用next获取下一个值
# 最后一个yield不能接受外部的值
# ---------------------------------------
# 123
# *** 1
# ======= hello
# 456
# *** 2
# 计算移动平均值
# def averager():
# total = 0.0
# count = 0
# average = None
# while True:
# term = yield average
# total += term
# count += 1
# average = total/count
#
#
# g_avg = averager()
# next(g_avg)
# print(g_avg.send(10))
# print(g_avg.send(30))
# print(g_avg.send(5))
# 列表推导式和生成器表达式
egg_list=['鸡蛋%s' %i for i in range(10)] #列表解析
# print(egg_list) # ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9']
#峰哥瞅着alex下的一筐鸡蛋,捂住了鼻子,说了句:哥,你还是给我只母鸡吧,我自己回家下
laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式
# print(laomuji)
# print(next(laomuji)) #next本质就是调用__next__
# print(laomuji.__next__())
# print(next(laomuji))
# <generator object <genexpr> at 0x1053c8b88>
# 鸡蛋0
# 鸡蛋1
# 鸡蛋2
# 总结:
# 1.把列表解析的[]换成()得到的就是生成器表达式
# 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存
# 3.Python不但使用迭代器协议,让for循环变得更加通用。大部分内置函数,也是使用迭代器协议访问对象的。
# 例如, sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,所以,我们可以直接这样计算一系列值的和:
sum(x ** 2 for x in range(4))
# 而不用多此一举的先构造一个列表:
sum([x ** 2 for x in range(4)])
# 小结
# 可迭代对象:
# 拥有__iter__方法
# 特点:惰性运算
# 例如:range(),str,list,tuple,dict,set
#
# 迭代器Iterator:
# 拥有__iter__方法和__next__方法
# 例如:iter(range()),iter(str),iter(list),iter(tuple),iter(dict),iter(set),reversed(list_o),map(func,list_o),filter(func,list_o),file_o
#
# 生成器Generator:
# 本质:迭代器,所以拥有__iter__方法和__next__方法
# 特点:惰性运算,开发者自定义
# 使用生成器的优点:
# 1.延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。
# 2.提高代码可读性
# 列表解析
# sum([i for i in range(100000000)]) # 内存占用大,机器容易卡死
# 生成器表达式
# sum(i for i in range(100000000)) # 几乎不占内存
# 生成器相关的面试题
def demo():
for i in range(4):
yield i
g=demo()
g1=(i for i in g)
g2=(i for i in g1)
print(g1)
print(g2)
print(list(g1))
print(list(g2))
# 为什么是这个结果?
# <generator object <genexpr> at 0x104881c78>
# <generator object <genexpr> at 0x104881cf0>
# [0, 1, 2, 3]
# []
Day-2-generator
最新推荐文章于 2024-05-18 09:59:00 发布