# 迭代器和生成器
# 迭代器:
# 双下方法:很少用 ,一般是通过其他方法触发的
# 可迭代协议——含有__iter__方法
# 迭代器协议——含有__iter__和__next__方法
# 可迭代的一定可以for循环
# 迭代器一定可迭代,可迭代对象通过调用__iter__方法就可得到一个生成器
# 迭代器特点
# 方便使用,但是迭代器中的数据只能取一次
# 节省内存空间
# 生成器:
# 本质上就是一个迭代器
# 生成器的表现形式
# 生成器函数
# 含有yield关键字的函数就是生成器函数
# 特点:
# 调用函数之后,返回一个生成器
# 每次调用next方法的时候就会取到一个值
# 知道取完最后一个值再执行next就会报错
# 取值方法:
# next
# for
# 数据类型的强制转换;此方法占内存
# 生成器表达式
# def generator():
# for i in range(200):
# yield "哇哈哈%s"%i
# g = generator()
# ret = list(g) #数据类型强制转换,占内存
# print(ret)
# g = generator() #调用函数得到一个生成器
# print(g)
# ret = g.__next__()
# print(ret)
# num = 0
# for i in g:
# num += 1
# if num >50:
# break
# print(i)
# def generator():
# print(123)
# content = yield 1
# print('====',content)
# print(456)
# arg = yield 2
# g1=generator()
# g2=generator()
# g1.__next__()
# g2.__next__()
# print('***',generator().__next__())
# print('***',generator().__next__())
# g = generator()
# ret = g.__next__()
# print('***',ret)
# ret = g.send('hello')
# print('***',ret)
# send:
# send获取下一个值的效果和next基本一致
# 只是在获取下一个值时,同时给上一个yield位置出传递一个参数
# 使用send的注意事项:
# 第一次使用生成器时,只能用next获取下一个值
# 最后一个yield无法接受外部值
# 计算移动平均值 avg = sum/count
# 10 20 30
# 10 15 20
# def average():
# sum = 0
# count = 0
# avg = 0
# while True:
# num = yield avg
# sum +=num
# count+=1
# avg = sum/count
# g = average()
# g.__next__() #激活发生器
# g1 = g.send(10) #执行到下一个yield才结束
# print(g1)
# g1=g.send(20)
# print(g1)
# 升级版,用一个装饰器去预激活一个生成器
# def actter(func):
# def inner(*args, **kwargs):
# ret = func(*args, **kwargs)
# ret.__next__() #在此激活生成器
# return ret
#
# return inner
#
# @actter
# def average():
# sum = 0
# count = 0
# avg = 0
# while True:
# num = yield avg
# sum += num
# count += 1
# avg = sum / count
#
# g = average()
# ret = g.send(10)
# print(ret)
# ret = g.send(90)
# print(ret)
# def l():
# yield from range(20)
# print(list(l()))
# 列表解析
# egg_list=['鸡蛋%s'%i for i in range(10)]
# #[存入方式 循环体 循环条件(可以有多个)]
# print(egg_list)
# egg_list = []
# for i in range(1000):
# egg_list.append('鸡蛋%s' % i)
# print(egg_list)
# print([i*i for i in range(10)])
# 生成器表达式
# 特点:
# 括号不一样
# 返回值不一样,几乎不占内存
# g = (i for i in range(10)) #用()
# print(g)
# for i in g:
# print(i)
# 老母鸡生成器,给蛋不如给老母鸡
# 老母鸡 = ('鸡蛋%s'%i for i in range(10))
# print(老母鸡)
# for 蛋 in 老母鸡:
# print(蛋)
# g = (i*i for i in range(10)) #未执行时与函数定义一样,什么都不做
# print(g)
# for i in g:
# print(i)
# 列表推导式
# 例一:30以内所有能被3整除的数
# print([i for i in range(31) if i%3==0])
# 例二:30以内所有能被3整除的数的平方
# print([i**2 for i in range(31) if i%3==0])
# 例三:找到嵌套列表中名字含有两个‘e’的所有名字
# names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
# ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
# print([name for lis in names for name in lis if name.count('e')>=2])
# 字典推导式
# 例一:将一个字典的key和value对调
# mcase = {'a': 10, 'b': 34}
# mcase_frequency = {mcase[k]: k for k in mcase}
# print(mcase_frequency)
# 例二:合并大小写对应的value值,将k统一成小写
# mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
# mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
# print(mcase_frequency)
# 集合推导式
# 例:计算列表中每个值的平方,自带去重功能
# print({i*i for i in [1,-1,3]})
# 可迭代对象:
# 拥有__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.
# 延迟计算,一次返回一个结果。也就是说,它不会一次生成所有的结果,这对于大数据量处理,将会非常有用。