python可迭代对象、迭代器和生成器
一、简介
1、关于迭代器和生成器
关于python的迭代器和生成器这两个概念,大多数程序员都认为其在功能上是类似的,在python官方文档中也有时认为迭代器就是生成器,其实这两种还是有一定的区别。
使用内置函数iter() 可以生成迭代器,使用内置函数next() 可以获得迭代器中的值。
第一点,从概念上: 在典型的迭代器设计模式中,迭代器用于遍历集合,从中产出元素,迭代器不能修改数据源中的值,只能原封不动地产出,而生成器可能无需遍历就能生成值。
第二点,从接口方面: python的迭代器协议定义了两个方法__iter__ 和__next__ ,生成器实现了这两个方法,因此从这方面来看,所有的生成器都是迭代器。
第三点、从实现方面: 生成器这种python语言结构可以使用两种方式编写:1、含有yield 关键字的函数,称之为生成器函数。2、使用生成器表达式。
2、关于可迭代对象
为什么是可迭代的?
在介绍可迭代对象之前,我们先了解一下python中序列可迭代的原因,序列之所以可以迭代是因为iter() 内置函数,iter() 内置函数有以下作用:
(1) 检查对象是否实现了__iter__ 方法,如果实现了就调用它,获取一个迭代器
(2) 如果没有实现__iter__ 方法,但是实现了__getitem__ 方法,python会创建一个迭代器,尝试按照顺序(从索引0)开始获取元素。
(3) 如果上述尝试均失败,python会抛出TypeError异常
什么是可迭代对象?
按照上面python序列可迭代的原因来看,Python中任意的对象,只要它定义了可以返回一个迭代器的 __iter__ 方法,或者定义了可以支持下标索引的 __getitem__ 方法,那么它就是一个可迭代对象。简单说,可迭代对象就是能提供迭代器的任意对象。
二、可迭代对象
可迭代对象可以使用内置iter()函数获取迭代器的对象,如果对象实现了能返回迭代器的__iter__方法,那么对象就是可以迭代的。序列都可以迭代;实现了__getitem__方法,而且其参数是从零开始的索引,这种对象也可以迭代。
按照上面我们对可迭代对象的定义,我们进行如下代码实验
import re
import reprlib
RE_WORD = re.compile('\w+')
class Sentence(object):
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text)
def __getitem__(self, index):
return self.words[index]
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text)
s = Sentence('My favorite language is python !')
print(s)
for word in s: print(word)
Sentence('My favorite ...e is python !')
My
favorite
language
is
python
在上述代码实验中,我们并没有重载__itet__ 方法,而是重载了__getitem__ 方法,我们自定义的Sentence类仍然是可以迭代的,说明我们之前对可迭代对象的定义正确。
我们来验证是否能够使用iter()内置函数来直接获取对象的迭代器,
s1 = Sentence('Hi Python')
it = iter(s1)
print(next(it))
print(next(it))
Hi
Python
结果表明,我能确实能够获得序列对象的迭代器。
三、迭代器
标准的迭代器需要实现的方法:
(1) __next__ 返回下一个可用的元素,如果没有元素,抛出StopIteration异常。
(2) __iter__ 返回self,以便在应该使用可迭代对象的地方使用迭代器,例如for循环中。
现在我们按照迭代的标准写法,来改写前一个列子的代码。
import re
import reprlib
RE_WORD = re.compile('\w+')
class Sentence(object):
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text)
def __repr__(self):
return "Sentence(%s)" % reprlib.repr(self.text)
def __iter__(self):
return SentenceIterator(self.words)
class SentenceIterator(object):
def __init__(self, words):
self.words = words
self.index = 0
def __next__(self):
try:
word = self.words[self.index]
except IndexError:
raise StopIteration
self.index += 1
return word
def __iter__(self):
return self
s1 = Sentence('My favorite language is Python!')
print(s1)
print('================================')
for word in s1: print(word)
it = iter(s1)
print('================================')
print(next(it))
print(next(it))
Sentence('My favorite ...ge is Python!')
================================
My
favorite
language
is
Python
================================
My
favorite
在构建迭代器对象和迭代器时经常会出现错误,原因是混淆了两者,要知道,可迭代的对象有一个__iter__ 方法,每次都实例化一个新的迭代器;而迭代器要实现__next__ 方法,返回单个元素,此外还要实现__iter__ 方法,返回迭代器本身。
小结: 可迭代的对象一定不能是自身的迭代器,也就是说,可迭代的对象必须实现__iter__ 方法,但是不能实现__next__ 方法。 另一方面,迭代器应该可以一直迭代,迭代器的__iter__ 方法应该返回自身。
四、生成器与生成器函数
1、生成器函数
先介绍什么是生成器函数,在普通函数定义中,不需要return,而是采用yield 关键字来“产生”值,该函数就是生成器函数。调用生成器函数时,会返回一个生成器对象,也就是说生成器函数是生成器工厂。
定义一个简单的生成器函数:
def gen_123():
for i in [1,2,3]:
yield i
it = gen_123()
print(next(it))
print(next(it))
print(next(it))
1
2
3
上述代码中,为了实现相同的功能,符合python编程风格的做法是,用生成器函数来代替SentenceIterator类。
import re
import reprlib
RE_WORD = re.compile('\w+')
class Sentence(object):
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text)
def __repr__(self):
return "Sentence(%s)" % reprlib.repr(self.text)
def __iter__(self):
for word in self.words:
yield word
s2 = Sentence('My favorite language is Pythooooon!')
print(s2)
print('================================')
for word in s2: print(word)
print('================================')
it = iter(s2)
print(next(it))
print(next(it))
Sentence('My favorite ...s Pythooooon!')
================================
My
favorite
language
is
Pythooooon
================================
My
favorite
注意我们在此,并没有定义迭代器类,而是使用生成器函数来代替迭代器的类,更加pythonic
2、生成器表达式
生成器表达式,和列表生成式字典生成式等类似,只不过将[ ] 替换成( )
it = (x for x in [1,2,3,4])
print(type(it))
print(next(it))
print(next(it))
print(next(it))
print(next(it))
<class 'generator'>
1
2
3
4
五、Reference
https://www.liaoxuefeng.com/wiki/1016959663602400/1017318207388128 https://www.runoob.com/python3/python3-iterator-generator.html https://py.eastlakeside.cn/book/DataStructures/generators.html 《FluentPython》
|