我是靠谱客的博主 老迟到热狗,最近开发中收集的这篇文章主要介绍迭代器 for循环的原理 生成器 yield迭代器for循环的原理生成器yield,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

迭代器

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

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

为什么要有迭代器

对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器

可迭代对象

要想了解迭代器为何物,必须事先搞清楚一个很重要的概念:可迭代对象(Iterable)。

从语法形式上讲,内置有__iter__方法的对象都是可迭代对象,字符串、列表、元组、字典、集合、打开的文件都是可迭代对象:

'hello'.__iter__
(1,2,3).__iter__
[1,2,3].__iter__
{'a':1}.__iter__
{'a','b'}.__iter__
open('a.txt').__iter__

迭代器对象

调用obj.__iter__()方法返回的结果就是一个迭代器对象(Iterator)。

迭代器对象是内置有__iter__和__next__方法的对象,打开的文件本身就是一个迭代器对象,执行迭代器对象.__iter__()方法得到的仍然是迭代器本身,而执行迭代器.__next__()方法就会计算出迭代器中的下一个值。 

迭代器是Python提供的一种统一的、不依赖于索引的迭代取值方式,只要存在多个“值”,无论序列类型还是非序列类型都可以按照迭代器的方式取值

可迭代对象转迭代器对象 __iter__

s = 'hello'
res = s.__iter__()
print(res)  # 得到的是迭代器对象的内存地址
# >>> <str_iterator object at 0x0000027734C7E908>


调用__next__迭代取值
l = [1, 2, 3]
res = l.__iter__()
print(res.__next__())  # >>> 1
print(res.__next__())  # >>> 2
print(res.__next__())  # >>> 3
print(res.__next__())  # >>> 值取完再取,报错 StopIteration

d = {'name': 'waller', 'age': 20, 'hobby': 'read'}
res = d.__iter__()
print(res.__next__())  # >>> name
print(res.__next__())  # >>> age
print(res.__next__())  # >>> hobby
print(res.__next__())  # >>> 值取完再取,报错 StopIteration

print(d.__iter__().__next__())  # >>> name
print(d.__iter__().__next__())  # >>> name
print(d.__iter__().__next__())  # >>> name
# 可迭代对象转成迭代器对象后取值,又重新把可迭代对象转成迭代器对象再取值,所以取的都是第一个值

# 文件本身就是迭代器对象,无论调用多少个__iter__ 都是一样的结果
with open('file.txt', 'r', encoding='utf-8') as f:
    pass
f_iter = f.__iter__()
print(f_iter is f)  # True 文件对象调用__iter__方法后的内存地址和调用前一样
f.__next__()  # 迭代器对象用__next__取文件里每行的内容

异常处理
d = {'name': 'waller', 'age': 20, 'hobby': 'read'}
res = d.__iter__()

while True:
    try:
        print(res.__next__())
    except StopIteration:
        print('值已取完')
        break
# 对迭代器对象循环取值,通过try + excep

迭代器总结

1.迭代就是重复的过程,每一次重复称为一次迭代,并且没次重复的结果是下一次重复的初始值

2.python必须要提供一种不依赖索引取值的迭代方式 -> 迭代器

  • 优点:

1.迭代器对象在内存中只是一个内存地址,不占空间

2.迭代器同一时刻在内存中只有一个值 ->更节省内存

  • 缺点:

1.只能往后取,并且是一次性的(索引取值更灵活)

2.无法统计迭代器的长度

for循环的原理

  • 1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic

  • 2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码

  • 3: 重复过程2,直到捕捉到异常StopIteration,结束循环

#基于for循环,我们可以完全不再依赖索引去取值了
dic={'a':1,'b':2,'c':3}
for k in dic:
    print(dic[k])

生成器

只要函数内部包含有yield关键字,那么函数名()的到的结果就是生成器,并且不会执行函数内部代码

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>

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

print(g.__iter__)  # <method-wrapper '__iter__' of generator object at 0x000002354AD2DEB8>
print(g.__next__)  # <method-wrapper '__next__' of generator object at 0x000002354AD2DEB8>

练习

自定义函数模拟range(1,7,2)

def my_range(start,stop,step=1):
    while start < stop:
        yield start
        start+=step

#执行函数得到生成器,本质就是迭代器
obj=my_range(1,7,2) #1  3  5
print(next(obj))
print(next(obj))
print(next(obj))
print(next(obj)) #StopIteration

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

#应用于for循环
for i in my_range(1,7,2):
    print(i)

yield

yield为我们提供了一种自定义迭代器对象的方法,yield所在的函数加括号执行就得到迭代器。

yield可以用于返回值,但不同于return,函数一旦遇到return就结束了,而yield可以保存函数的运行状态挂起函数,用来返回多次值

def dog(name):
    print('%s 准备开吃'%name)
    while True:
        food = yield
        print('%s 吃了 %s'%(name,food))
g = dog('xx')
g.__next__()  # 必须先将代码运行至yield 才能够为其传值
g.send('狗不理包子')  # 给yield左边的变量传参  触发了__next__方法
g.send('饺子')
'''
xx 准备开吃
xx 吃了 狗不理包子
xx 吃了 饺子
'''

 表达式形式的yield也可以用于返回多次值,即变量名=yield 值的形式,如下

def eater():
    print('Ready to eat')
    food_list=[]
    while True:
       food=yield food_list
       food_list.append(food)
 
e=eater()
next(e)
# Ready to eat
# []
e.send('蒸羊羔')
# ['蒸羊羔']
e.send('蒸熊掌')
# ['蒸羊羔', '蒸熊掌']
e.send('蒸鹿尾儿')
# ['蒸羊羔', '蒸熊掌', '蒸鹿尾儿'

yield后面跟的值就是调用迭代器__next__方法你能得到的值

yield会将函数暂停住

yield既可以返回一个值也可以返回多个值 并且多个值也是按照元组的形式返回

yield支持外界为其传参(了解)

最后

以上就是老迟到热狗为你收集整理的迭代器 for循环的原理 生成器 yield迭代器for循环的原理生成器yield的全部内容,希望文章能够帮你解决迭代器 for循环的原理 生成器 yield迭代器for循环的原理生成器yield所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部