Python3 迭代器与生成器

Python3 迭代器与生成器

目录

迭代

迭代器(Iterator)

迭代器有两个基本的函数:iter() 和 next()

小结

生成器(generator)

小结


 

迭代

如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们称为迭代(Iteration)。

Python的for循环抽象程度要高于C的for循环,因为Python的for循环不仅可以用在list或tuple上,还可以用在其他可迭代对象上。

只要是可迭代对象(Iterable),就可以进行迭代,比如dict就可以迭代:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

d = {"name": "Jane", "age": 18, "sex": "woman"}
print("打印字典中的keys:")
for k in d:  # 默认情况下,字典d迭代的是key
    print(k)
print("\r")

print("打印字典中的values:")
for v in d.values():  # values()返回一个包含字典中values的迭代器
    print(v)
print("\r")

print("打印字典中的(key,value):")
for i in d.items():  # items()返回一个列表,字典中的(键,值)以元组的形式作为该列表中的元素
    print(i)
print("\r")

print("打印字典中的key:value:")
for k, v in d.items():
    print(k, v, sep=":")

因为dict的存储不是按照list的方式顺序排列,所以,迭代出的结果顺序很可能不一样。

默认情况下,dict迭代的是key。如果要迭代value,可以用for value in d.values(),如果要同时迭代key和value,可以用for k, v in d.items()

由于字符串也是可迭代对象,因此,也可以作用于for循环:

>>> for ch in 'ABC':
...     print(ch)
...
A
B
C

所以,任何可迭代对象都可以作用于for循环,包括我们自定义的数据类型,只要符合迭代条件,就可以使用for循环。

通过collections模块的Iterable类型,可以判断一个对象是否是可迭代对象:

>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False

迭代器(Iterator)

迭代器是一个对象,简称为迭代器对象(Iterator)。迭代器从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不能后退。

通过collections模块的Iterator类型,可以判断一个对象是否是迭代器:

>>> from collections import Iterator
>>> isinstance([1,2],Iterator)
False  # 列表不是一个迭代器对象

迭代器有两个基本的函数:iter() 和 next()

这两个函数都是Python3的内置函数。

iter():用于创建迭代器对象。例如:

tuple、list、dict、str等虽然是Iterable(可迭代对象),但却不是Iterator(迭代器对象)。把list、dict、str等Iterable变成Iterator可以使用iter():

>>> isinstance(iter([1,2]),Iterator)
True

为什么list、dict、str等数据类型不是Iterator?

这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。

Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。

next():可以不断调用迭代器对象并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值。例如:

>>>list=[1,2,3,4]
>>> it = iter(list)    # 创建迭代器对象
>>> print (next(it))   # 输出迭代器的下一个元素
1
>>> print (next(it))
2
>>>

迭代器对象可以使用for语句进行遍历:

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
 
list=[1,2,3,4]
it = iter(list)    # 创建迭代器对象
for x in it:
    print (x, end=" ")

小结

凡是可作用于for循环的对象都是Iterable类型(可迭代对象);

凡是可作用于next()函数的对象都是Iterator类型(迭代器对象),它们表示一个惰性计算的序列;

集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。


生成器(generator)

在 Python 中,使用了 yield 关键字的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作。更简单点理解生成器就是一个迭代器,可作用于for循环。

调用生成器函数:在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。

调用一个生成器函数,返回的是一个迭代器对象。

举个简单的例子,定义一个generator,依次返回数字1,3,5:

def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

调用该generator时,首先要生成一个generator对象,然后用next()函数不断获得下一个返回值:

>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next(o)就报错。

我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

>>>for x in odd():
...    print(x)

Python的for循环本质上就是通过不断调用next()函数实现的,例如:

for x in [1, 2, 3, 4, 5]:
    pass  #空语句,即什么都不执行

实际上完全等价于:

# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break

小结

理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值