迭代器和生成器

迭代器

迭代的含义

  1. 重复
  2. 下一次重复是基于上一次的结果

可迭代对象和迭代器

  1. python中,对于有序对象,比如列表、元组、字符串,可以通过索引的方式来遍历元素。像字典和集合这样的无序的对象,没办法索引。
    为了提供一种不依赖于索引的迭代方式,python为一些对象内置了 obj.__iter__方法:有这种方法的obj称为可迭代对象。

  2. 一个可迭代对象执行obj.__iter__()得到的结果就是迭代器;iter(obj)等价于obj.__iter__()

  3. 迭代器有__iter____next__两种方法。对一个迭代器执行Iterator.__iter__()方法得到这个迭代器本身。对一个迭代器每执行一次Iterator.__next__()方法,就可以迭代出一个元素。

  4. 如何判断一个对象是否是可迭代对象或迭代器:

from collections import Iterable, Iterator   # 导入模块
isinstance(obj, Iterable)   # 判断 obj 是否是 Iterable 的实例,返回True/False
isinstance(obj, Iterator)   # 判断 obj 是否是 Iterator 的实例,返回True/False

迭代器的优点

  1. 提供了一种不依赖于索引的取值方式
  2. 惰性计算,节省内存

迭代器的缺点

  1. 取值不如按照索引取值方便
  2. 一次性的,只能往后走,不能往前退,调用obj.__next__()方法执行,最后一个元素迭代完后抛出StopIteration
  3. 因此,也无法获取长度

for i in obj:

for i in obj:   # 执行 obj = obj.__iter__()
    print(i)    # 执行obj.__next__(),把每一次的返回值给i 并打印出来,直到for捕获到StopIteration,结束

知道了这个原理后,我们也可以用while方式来实现迭代。

l = [1,2,3,4]
l = iter(l)     # 将列表转化为迭代器
while True:
    print(next(l))  # 调用next方法迭代元素,直到抛出StopIteration

为了避免抛出StopIteration,可以使用try: exception :捕获它,并设置处理方式:

l = [1,2,3,4]
l = iter(l)
while True:
    try:    # 在可能出现异常的语句前设置try:
        print(next(l))
    except StopIteration:   # 捕捉StopIteration异常
        break   # 异常处理

生成器

生成器函数:

函数体包含yield关键字,该函数的执行结果是生成器函数。

def step():
    print('first-------->')
    yield 1
    print('second-------->')
    yield 2
    print('third-------->')
    yield 3
    print('fourth-------->')    # 函数最后没有return,默认执行return None
# 执行函数step()就是一个生成器
print(type(step())) # 打印结果为:<class 'generator'>
g = step()
from collections import Iterator
print(isinstance(g, Iterator))
# 打印结果是True, 因此生成器就是迭代器,具有迭代器的方法 __next__
print(next(g))  # 执行一次next(g),(等价于g.__next__()),触发一次函数执行,直到遇到yield,打印出yield返回值
print(next(g))  #
print(next(g))
print(next(g))
print(next(g))

yield的功能

  1. 与return类似,都可以返回值,但通过yield可以返回多次值,而return只能返回一次。
  2. 为函数封装__iter____next__方法,把函数的执行(函数名+())结果做成了迭代器。
  3. 遵循迭代器的取值方式obj.__next__(), 触发函数的执行,函数暂停与再继续的状态由yield保存。

实例:

计数器

def countdown(n):
    print('starting counting')
    while n > 0:
        yield n     # 碰到yield暂停,返回当前n的值,下次从当前处往下执行。
# 因为生成器也是迭代器,具有迭代器特性:一次性的,只能往前走
        n -= 1
    print('stop counting')
g = countdown(5)
print(next(g))  # next迭代g的元素,直到抛出StopIteration,另外,StopIteration的打印位置是随机的。
...

我们也可以用 for i in g 语句来自动捕获 StopIteration ,来结束迭代:

for i in g:
    print(i)
# 运行结果如下:
# starting counting
# 5
# 4
# 3
# 2
# 1
# stop counting

注意:通过将生成器函数countdown(5)引用给g, 每次执行g,都是在迭代同一个生成器,返回的值是前后连续的。而每次直接执行countdown(5),都是在产生一个新的生成器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值