0%

Python中生成器、迭代器和可迭代对象

可迭代对象

  • 如果对象实现了能返回迭代器的__iter__方法,那么对象是一个可迭代的。
  • 如果对象实现了__getitem__方法,且其参数是从零开始的索引,那么这种对象也是可迭代的。
  • 可迭代对象和迭代器之间的关系:Python从可迭代对象中获取迭代器

    迭代器

  • 迭代器是这样的对象:实现了无参数的__next__方法,返回序列的下一个元素,如果没有元素了,那么抛出StopIteration异常。Python中的迭代器还实现了__iter__方法,因此迭代器也可以迭代
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 内置函数iter(obj),要求obj是一个可迭代对象
class Test: # 可迭代对象测试类
def __init__(self, content):
self.content = list(content)

def __iter__(self): # 实现该方法后,可以通过iter()方法获取对象的迭代器
return iter(self.content) # 返回一个迭代器(即返回的对象可以通过next方法获取下一个元素)

if __name__ == '__main__':
t = Test([1, 2, 3, 4]) # t是一个可迭代对象
# 从可迭代对象t中获取迭代器it
it = iter(t) # 由于t对象实现了__iter__方法,故可以调用内置函数iter()返回是一个迭代器
while True:
try:
print(next(it)) # it是迭代器,故可以使用next()方法获取下一个元素
except StopIteration:
del it
break
# 如果要遍历一个可迭代对象,则需要通过it = iter(t)获取迭代器,再使用next(it)方法遍历
# 如果要遍历一个迭代器,则可以直接通过next()方法遍历

class TestIterator: # 迭代器测试类
def __init__(self, content):
self.content = list(content)
self.index = 0

def __iter__(self):
return self # 迭代器应该一直可以迭代,迭代器的__iter__应该返回自身

def __next__(self):
try:
cont = self.content[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return cont

if __name__ == '__main__':
ti = TestIterator([1, 2, 3, 4, 5]) # ti是一个迭代器,可以直接通过next(ti)获取下一个元素
while True:
try:
print(next(ti))
except StopIteration:
del ti
break

说明:

  • 迭代器一定是可迭代对象,但可迭代对象不一定是生成器
  • 因为迭代器只需__next____iter__两个方法,所以除了调用next()方法,以及捕获StopIteration异常之外,没有办法检查是否还有遗留元素。此外,也无法“还原”迭代器。如果想再次迭代,那就要调用iter(…),传入之前构建迭代器的可迭代对象,传入迭代器本身没用,因为Iterator.__iter__方法的实现方式是返回实例本身,所以传入迭代器无法还原已经耗尽的迭代器。

生成器

  • 生成器函数:只要python函数的定义体中有yield关键字,该函数就是生成器函数。调用生成器函数时会返回一个生成器对象。也就是说生成器函数时生成器工厂。
  • 普通函数与生成器函数在句法上的唯一区别是,后者的定义体中有yield关键字。
  • 生成器是迭代器,会生成原给yield关键字的表达式的值。
  • 生成器表达式:生成器表达式是语法糖,完全可以换成生成器函数。使用生成器表达式无需先定义函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def testGenerator(): # 生成器函数,用于获取生成器对象
for i in range(3):
yield i

if __name__ == '__main__':
t1 = testGenerator() # 通过调用生成器函数testGenerator获取生成器对象t1
for i in t1:
print(i)
print("----------")
t2 = testGenerator() # t2是一个生成器对象,可以通过next(t2)获取下一个元素,也是一个迭代器
while True:
try:
print(next(t2))
except StopIteration:
del t2
break
# 生成器表达式测试
t3 = (x*3 for x in testGenerator()) # 把生成器表达式返回的值赋值给t3,t3是一个生成器
print(t3) # <generator object <genexpr> at 0x0000020D5ABE5F90>
for i in t3: # 只有迭代生成器对象时,生成器函数testGenerator的定义体才会真正执行。for循环每次迭代时会隐式调用next(t3)。
print(i)
t4 = [x*3 for x in testGenerator()] # 列表推导,立刻迭代生成器函数testGenerator生成的生成器对象中的元素
print(t4) # [0, 3, 6]