Python开发【第五篇】:迭代器与生成器

一、迭代器 

迭代器的概念
#迭代器即迭代的工具,那什么是迭代呢?
#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值
迭代器协议和for循环工作机制
#for循环的工作原理
#1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic
#2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码
#3: 重复过程2,直到捕捉到异常StopIteration,结束循环

# l = [1,2,3,4,5,6,7,8,9]
#
# iter_l = l.__iter__()
#
# print(iter_l.__next__())
# print(iter_l.__next__())
# print(next(iter_l))  #next本质就是调用__next__
迭代器的优缺点
#优点:
  - 提供一种统一的、不依赖于索引的迭代方式
  - 惰性计算,节省内存
#缺点:
  - 无法获取长度(只有在next完毕才知道到底有几个值)
  - 一次性的,只能往后走,不能往前退

 二、生成器

什么是生成器

#只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,当调用函数并且不会执行函数内部代码,只有得到__next__指令时才会往下执行

def func():
    print('====>first')
    yield 1
    print('====>second')
    yield 2
    print('====>third')
    yield 3
    print('====>end')

g=func()
print(g) #<generator object func at 0x0000000002184360> 
 1、生成器函数
#1、生成器函数
def test():
    yield 1
    yield 2

g = test()

print(g.__next__())
print(g.__next__())
print(next(g))



def product_baozi():
    ret = []
    for i in range(10):
        ret.append('鸡蛋%s' %i)
    return ret
#缺点1:占空间大
#缺点2:效率低,因为要全部蛋下完才可以



def product_baozi():
    for i in range(100):
        print('正在生产包子')
        yield '一屉包子%s' %i
        print('开始卖包子')
pro_g = product_baozi()

baozi1 = pro_g.__next__()
baozi1 = pro_g.__next__()
print(baozi1)


#也可以这么写
baozi = product_baozi()
for i in baozi:
    print(i)

 返回值是yield 可以多个yield,yield相当于return,yield可以保持函数的运行状态

2、生成式表达式
#2、生成式表达式
lmj = ('鸡蛋%s' %i for i in range(10)) #生成器表达式
print(lmj.__next__())
print(next(lmj))

n = sum(i for i in range(10000))
print(n)

sum(list(range(1000000000)))
生成器就是迭代器
g.__iter__
g.__next__
#2、所以生成器就是迭代器,因此可以这么取值
res=next(g)
print(res)

 生成器表达式之后就有一个__next__方法

三元表达式
name = 'aln'
res = 'sb' if name == 'alb' else '帅哥'
print(res)
列表解析
egg_list = []
for i in range(10):
    egg_list.append('鸡蛋%s' %i)
print(egg_list)

#这种方法更快速
l = ['鸡蛋%s' %i for i in range(10)] #列表解析
l1 = ['鸡蛋%s' %i for i in range(10) if i>5]
# l1 = ['鸡蛋%s' %i for i in range(10) if i>5 else i] #没有四元表达式
print(l)
prinzt(l1)
总结:

# 1、把列表解析的[]换成()得到的就是生成器表达式

# 2、列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存

 注意:

#列表解析
sum[i for in range(100000000000000)] # 内存占用大,机器容易卡死
    
#生成器表达式
sum(i for i in range(100000000000000))# 几乎不占用内存
 例子
获取每个省占用全国人口的百分比(通过获取文件的每一行)
#获取每个省占用全国人口的百分比
"""人口文件的内容
{'name':'山东','population':10}
{'name':'山西','population':888}
{'name':'河南','population':765}
{'name':'河北','population':6546}
{'name':'广西','population':353}
"""
def get_population_count():
    with open('人口普查', 'r',encoding='utf-8') as f:
        for i in f:   # 每次循环一次,取出来的是一行的内容
            yield i
g = get_population_count()

#g.__next__()生成的是字符串,需要通过使用eval函数将字符串转换成字典模式
s1 = eval(g.__next__())
print(g.__next__())
print(type(s1))
print(s1['population'])

# #方法一、获取总人口
# total_population = 0
# for i in g:
#     p_dic = eval(i) #通过eval将字符串获取成字典形式
#     print(p_dic['population'])
#     total_population += eval(i)['population']
# print('总人口%s' %total_population)


#方法二、获取总人口
all_population = sum(eval(i)['population'] for i in g)
print('总人口%s' %all_population)

注意:迭代只迭代一次,上面方法一用了迭代,再用方法二就会得到迭代的值

g.__next__()生成的是字符串,需要通过使用eval函数将字符串转换成字典模式
s1 = eval(g.__next__())

 并发编程,一边吃包子,一边生成,通过send函数,然后通过yield来接收
yield 相当于return控制的是函数的返回值
x= yield的另一个特性,接收send传过来的值,赋值给x
def test():
    print('开始啦')
    first = yield 1  #first = None
    print('第一次',first)
    sec = yield 2
    print('第二次',sec)
    yield

t = test()
print(t.__next__())
t.send(None)
t.send('传给停留yield的那个位置的yield')



#*****************************************************************************************************************************************************************************************************************************************************************************


import time
def consumer(name):
    print('我是[%s], 我准备开始吃包子'%(name))
    while True:
        baozi = yield
        time.sleep(1)
        print('%s 很开心把[%s]吃掉了'%(name,baozi))

def producer():
    c1 = consumer('1号选手')
    c2 = consumer('1号选手')
    c1.__next__()
    c2.__next__()
    for i in range(10):
        time.sleep(1)
        c1.send('肉馅 %s' %i)
        c2.send('肉馅 %s '%i)

producer()

注意:yield 相当于return控制的是函数的返回值
x= yield的另一个特性,接收send传过来的值,赋值给x

  • 55
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值