Python-19-迭代器和生成器

Posted newmet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python-19-迭代器和生成器相关的知识,希望对你有一定的参考价值。

一、迭代器

迭代器协议:
1.迭代器协议是指:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,
要么就引起一个StopIteration异常,以终止迭代 (只能往后走不能往前退)#
2.可迭代对象:实现了迭代器协议的对象(如何实现:对象内部定义一个__iter__()方法)
3.协议是一种约定,可迭代对象实现了迭代器协议,python的内部工具(如for循环,sum,min,max函数等)
使用迭代器协议访问对象

for 循环机制:
1、for循环的本质:循环所有对象,全都是使用迭代器协议。
2、for循环就是基于迭代器协议提供了一个统一的可以遍历所有对象的方法,即在遍历之前,先调用对象
的__iter__方法将其转换成一个迭代器,然后使用迭代器协议去实现循环访问,这样所有的对象就都
可以通过for循环来遍历了,
3、列表,字符串,元组,字典,集合,文件对象等本质上来说都不是可迭代对象,在使用for循环的时候
内部是先调用他们内部的_iter_方法,使他们变成了可迭代对象,然后在使用可迭代对象的_next_方
法依次循环元素,当元素循环完时,会触发StopIteration异常,for循环会捕捉到这种异常,终止迭代
4、访问方式:下标方式访问、迭代器协议访问、for循环访问
# 1)下标访问方式--索引
li = [1,2,3,4]
print(li[0])                # 下标访问(索引)

index = 0
while index < len(li):
    print(li[index])
    index += 1


# 2)迭代器协议访问
li = [1,2,3,4]
f = li.__iter__()           # 第一步,先通过内部的_iter_方法,先把对象变成可迭代对象
print(f.__next__())         # 对可迭代对象用_next_方法取值
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())         # StopIteration,超出边界会报错
print(next(f))                # next(f) 就是 f.__next__()
print(next(f))

# 3)for循环访问
li = [1,2,3,4]
for i in li:                # li_iter = li._iter_()
    print(i)                # li_iter._next_

# 4)用while去模拟for循环做的事情
li = [1,2,3,4]
diedai_l=li.__iter__()
while True:
    try:
        print(diedai_l.__next__())
    except StopIteration:
        print(迭代完毕了,循环终止了)
        break

二、生成器

生成器类似于一种数据类型,这种数据类型自动实现了迭代器协议(其他的数据类型需要调用自
己内置的__iter__方法),所以生成器就是可迭代对象

生成器分类及在python中的表现形式:(Python有两种不同的方式提供生成器)
1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次
返回一个结果,在每个结果中间,挂起函数的状态,以便下次重它离开的地方继续执行
2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建
一个结果列表,按需取出对象

为何使用生成器之生成器的优点:
Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立
即产生结果。这也是生成器的主要好处。

########## 生成器小结 ###########
1、是可迭代对象
2、实现了延长计算、升内存
3、生成器本质和其他的数据类型一样,都是实现了迭代器协议,只不过生成器附加了一个延迟计算省内存的好处,
其余的同迭代对象没有这点好处。
########## 生成器小结 ###########

------------------ 1、生成器表达式 ------------------
# 1)三元表达式:
f = result = 值1 if 条件 else 值2      # True 输出值1;False 输出值2.
name = "newmet"
f = "TRUE_1" if name == "newmet" else "FALSE_1"
print(f)

# 2)列表解析:
# s = [三元表达式],列表解析生成的是一个真实存在于内存中的列表,对于比较大的列表,比较耗内存空间
count = [x for x in range(10)]  # 列表解析
l = ["苹果%s" % i for i in range(10)]  # 列表解析
print(l)  # 结果:[‘苹果0‘, ‘苹果1‘, ‘苹果2‘, ‘苹果3‘, ‘苹果4‘, ‘苹果5‘, ‘苹果6‘, ‘苹果7‘, ‘苹果8‘, ‘苹果9‘]
l1 = ["苹果%s" % i for i in range(10) if i > 5]
print(l1)  # 结果:[‘苹果6‘, ‘苹果7‘, ‘苹果8‘, ‘苹果9‘]

# 3)生成器表达式---[] 变成 ()
# 列表解析
sum([i for i in range(1000000)])  # 内存占用大,机器容易卡死
# 生成器表达式
sum(i for i in range(1000000))    # 几乎不占内存
# sum函数是Python的内置函数,该函数使用迭代器协议访问对象,而生成器实现了迭代器协议,不用多此一举先生成列表

l2 = ("苹果%s" % i for i in range(10))  # [] 变成 () 生成器表达式!!!!!!
print(l2)  # 结果:<generator object <genexpr> at 0x00000000037F9930> 内存地址
print(l2.__next__())  # 结果:苹果0
print(l2.__next__())  # 结果:苹果1
print(next(l2))  # 结果:苹果2
------------------ 2、生成器函数 ------------------
def test():
    yield 1         # 相当于return,不同于return,yield可以返回多个值
    yield 2
    yield 3

res = test()
print(res)             # 结果:<generator object test at 0x00000000037F9930> 内存地址
print(res.__next__())  # 结果:1   保留当前执行状态,下次执行从上次状态处继续往下执行
print(res.__next__())  # 结果:2
print(res.__next__())  # 结果:3   执行只能一直往前走,不能往后,只能执行一次,执行完继续执行会触发StopIteration

# 例1:母鸡下蛋
def xiadan():
    for i in range(10):
        yield "鸡蛋%s"%i
f = xiadan()
# for j in f:
#     print(j)
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())
print(f.__next__())

# 例2:人口普查
def get_population():
    with open("人口普查", "r", encoding="utf-8") as f:
        for i in f:
            yield i


g = get_population()
all_g = sum(eval(i)[population] for i in g)
print(all_g)

# 例3:吃包子

# 生产包子函数:
import time
def producer():
    ret=[]
    for i in range(100):
        time.sleep(0.1)
        ret.append("包子%s" %i)
    return ret
# 吃包子函数:
def consumer(res):
    for index,baozi in enumerate(res):
        time.sleep(0.1)
        print("第%s个人,吃了%s" %(index,baozi))
res = producer()
consumer(res)
# 这样的生产与消费是:先生产完包子,再去卖,效率太低,不符合实际需求。

# 伪并发
# send():可对yield函数传参数,参数会赋值给yield函数前的变量,通过send()可实现伪并发功能!!!!!!

import time #导入时间模块
def consumer(name):
    print("我是%s,我准备吃包子了"%name)
    while True:
        baozi = yield
        time.sleep(1)
        print("我是%s,我把包子%s吃掉了"%(name,baozi))
def producer(x):
    user_name = consumer(x)
    user_name.__next__()
    for i in range(100):
        time.sleep(1)
        user_name.send(i)#将i赋值给consumer()函数中yield前面的包子,下次执行时从此往后执行
use_name = input("欢迎您!请问怎么称呼您:")
print("好的,麻烦请稍等!包子马上就给您端上来")
producer(use_name)
三、生产者消费者模型
import time
# 消费者--程序
def consumer(name):
    print("我是[%s],我准备吃包子了;" %name)
    while True:
        baozi = yield
        time.sleep(1)
        print("%s 很开心的把[%s]吃掉了。" %(name,baozi))
# 生产者--程序
def producer():
    v1=consumer("newmet1")
    v2=consumer("newmet2")
    v1.__next__()
    v2.__next__()
    for i in range(10):
        time.sleep(1)
        v1.send("包子%s" %i)          # 将i赋值给producer()函数中yield前面的包子,下次执行时从此往后执行
        v2.send("包子%s" %i)
producer()
 




































以上是关于Python-19-迭代器和生成器的主要内容,如果未能解决你的问题,请参考以下文章

迭代器和生成器

python函数:迭代器和生成器

python函数:迭代器和生成器

迭代器和生成器函数

Python中迭代器和生成器的区别与联系

迭代器和生成器