迭代器 生成器

——迭代器

 

一 迭代器介绍

迭代器即用来迭代取值的工具,而迭代是重复反馈过程的活动,其目的通常是为了逼近所需的目标或结果,每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值,单纯的重复并不是迭代

while True:
    msg = input('>>: ').strip()
    print(msg)

 

下述while循环才是一个迭代过程,不仅满足重复,而且以每次重新赋值后的index值作为下一次循环中新的索引进行取值,反复迭代,最终可以取尽列表中的值

goods=['mac','lenovo','acer','dell','sony']

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

1.1 可迭代对象

通过索引的方式进行迭代取值,实现简单,但仅适用于序列类型:字符串,列表,元组。对于没有索引的字典、集合等非序列类型,必须找到一种不依赖索引来进行迭代取值的方式,这就用到了迭代器。

要想了解迭代器为何物,必须事先搞清楚一个很重要的概念:可迭代对象(Iterable)。从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象:

{'name':'egon'}.__iter__
{7,8,9}.__iter__
……

1.2 迭代器对象

调用obj.iter()方法返回的结果就是一个迭代器对象(Iterator)。迭代器对象是内置有iter和next方法的对象,打开的文件本身就是一个迭代器对象,执行迭代器对象.iter()方法得到的仍然是迭代器本身,而执行迭代器.next()方法就会计算出迭代器中的下一个值。 迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值

 
>>> s={1,2,3} # 可迭代对象s
>>> i=iter(s)  # 本质就是在调用s.__iter__(),返回s的迭代器对象i,
>>> next(i) # 本质就是在调用i.__next__()
1
>>> next(i)
2
>>> next(i)
3
>>> next(i)  #抛出StopIteration的异常,代表无值可取,迭代结束
 

 

二 for循环原理

有了迭代器后,我们便可以不依赖索引迭代取值了,使用while循环的实现方式如下

 
goods=['mac','lenovo','acer','dell','sony']
i=iter(goods) #每次都需要重新获取一个迭代器对象
while True:
    try:
        print(next(i))
    except StopIteration: #捕捉异常终止循环
        break
 

 

for循环又称为迭代循环,in后可以跟任意可迭代对象,上述while循环可以简写为

goods=['mac','lenovo','acer','dell','sony']
for item in goods:   
    print(item)

 

for 循环在工作时,首先会调用可迭代对象goods内置的iter方法拿到一个迭代器对象,然后再调用该迭代器对象的next方法将取到的值赋给item,执行循环体完成一次循环,周而复始,直到捕捉StopIteration异常,结束迭代。

 

三 迭代器的优缺点

基于索引的迭代取值,所有迭代的状态都保存在了索引中,而基于迭代器实现迭代的方式不再需要索引,所有迭代的状态就保存在迭代器中,然而这种处理方式优点与缺点并存:

3.1 优点:

1、为序列和非序列类型提供了一种统一的迭代取值方式。

2、惰性计算:迭代器对象表示的是一个数据流,可以只在需要时才去调用next来计算出一个值,就迭代器本身来说,同一时刻在内存中只有一个值,因而可以存放无限大的数据流,而对于其他容器类型,如列表,需要把所有的元素都存放于内存中,受内存大小的限制,可以存放的值的个数是有限的。

 

3.2 缺点:

1、除非取尽,否则无法获取迭代器的长度

2、只能取下一个值,不能回到开始,更像是‘一次性的’,迭代器产生后的唯一目标就是重复执行next方法直到值取尽,否则就会停留在某个位置,等待下一次调用next;若是要再次迭代同个对象,你只能重新调用iter方法去创建一个新的迭代器对象,如果有两个或者多个循环使用同一个迭代器,必然只会有一个循环能取到值。

 

python学习18——生成器基础

 

一 生成器与yield

若函数体包含yield关键字,再调用函数,并不会执行函数体代码,得到的返回值即生成器对象

 
>>> def my_range(start,stop,step=1):
...     print('start...')
...     while start < stop:
...         yield start
...         start+=step
...     print('end...')
... 
>>> g=my_range(0,3)
>>> g
<generator object my_range at 0x104105678>
 

生成器内置有__iter__和__next__方法,所以生成器本身就是一个迭代器

>>> g.__iter__
<method-wrapper '__iter__' of generator object at 0x1037d2af0>
>>> g.__next__
<method-wrapper '__next__' of generator object at 0x1037d2af0>

 

因而我们可以用next(生成器)触发生成器所对应函数的执行,

 
>>> next(g) # 触发函数执行直到遇到yield则停止,将yield后的值返回,并在当前位置挂起函数
start...
0
>>> next(g) # 再次调用next(g),函数从上次暂停的位置继续执行,直到重新遇到yield...
1
>>> next(g) # 周而复始...
2
>>> next(g) # 触发函数执行没有遇到yield则无值返回,即取值完毕抛出异常结束迭代
end...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
 

 

既然生成器对象属于迭代器,那么必然可以使用for循环迭代,如下:

 
>>> >>> for for i i in in countdowncountdown((33):
): ...     ...     printprint((ii)
) ... 
...  countdown countdown start
start 3
3 2
2 1
1 DoneDone!!
 

 

有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值

 

----------------------------------------------------------------------------------------------------------------------------------------------------------(自己)

1、什么是迭代器
迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复
都是基于上一次的结果而继续的,单纯的重复并不是迭代

2、为何要有迭代器
迭代器是用来迭代取值的工具,而涉及到把多个值循环取出来的类型
有:列表、字符串、元组、字典、集合、打开文件

l=['egon','liu','alex']
i=0
while i < len(l):
print(l[i])
i+=1

上述迭代取值的方式只适用于有索引的数据类型:列表、字符串、元组
为了解决基于索引迭代器取值的局限性
python必须提供一种能够不依赖于索引的取值方式,这就是迭代器


# 列表,元组,字典就,集合,文件 可迭代对象
# 文件 迭代器

# __iter__ () 内置带有 就是可迭代对象
#__next__() 取值 迭代器


# try:(触发异常)
# 程序
# except StopAsyncIteration: 捕捉异常
# break

# with open("账号密码",mode="r",encoding="utf8")as f:
# res=f.__iter__()
# while True: #注意缩进
# try:
# print(res.__next__())
# except StopIteration:
# break


# 如何得到自定义的迭代器:
# 在函数内一旦存在yield关键字,调用函数并不会执行函数体代码
# 会返回一个生成器对象,生成器即自定义的迭代器

def func():
print('第一次')
yield 1
print('第二次')
yield 2
print('第三次')
yield 3
print('第四次')


# g=func()
# print(g)
# 生成器就是迭代器
# g.__iter__()
# g.__next__()


# 会触发函数体代码的运行,然后遇到yield停下来,将yield后的值
# 当做本次调用的结果返回
# res1=g.__next__()
# print(res1)
#
#
# res2=g.__next__()
# print(res2)
#
# res3=g.__next__()
# print(res3)
#
# res4=g.__next__()

 

# len('aaa') # 'aaa'.__len__()

# next(g) # g.__next__()
# iter(可迭代对象) # 可迭代对象.__iter__()

# 应用案列
def my_range(start,stop,step=1):
# print('start...')
while start < stop:
yield start
start+=step
# print('end....')


# g=my_range(1,5,2) # 1 3
# print(next(g))
# print(next(g))
# print(next(g))

for n in my_range(1,7,2):
print(n)

 

# 总结yield:
# 有了yield关键字,我们就有了一种自定义迭代器的实现方式。yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值




# 自定义迭代器=生成器
def func():
print("第一个")
yield 1
print("第二个")
yield 2 #返回一个可迭代对象 相当于地址类的


a=func()
res=a.__next__() #返回值是yield
print(res)


# def my_range(start,stop,step=1):         自定义range():
#     while start<stop:
#         yield start                   #yield可以暂时挂起返回值 暂时停止运行挂起
#         start+=step




# # g=my_range(1,10) #发挥yield
# # print(iter(g)) #产生一个可迭代对象
# # print(next(g)) #产生迭代器返回yield的值 运行一次向后 输出一次
# # print(next(g))
# # print(next(g))
#
# for i in my_range(1,50,2): for循环
# print(i) #不需要next()迭代器产生值
 

 



posted @ 2021-03-16 19:24  欧阳锦涛  阅读(40)  评论(0)    收藏  举报
TOP 底部