导读
这篇文章主要介绍了 python 当中的迭代器与生成器,在涉及到大数量的场景应该考虑使用迭代器与生成器。
可迭代对象
如果一个对象实现了 __iter__
方法,那么我们就称它是一个可迭代对象。如果没有实现 __iter__
而实现了
__getitem__
方法,并且其参数是从0开始索引的,这种对象也是可迭代的,比如说序列。
使用 iter
内置函数可以获取迭代器的对象,当解释器需要迭代对象时,会自动调用 item(x)
:
- 如果对象实现了
__iter__
方法,获取一个迭代器 - 如果没有实现
__iter__
,但是实现了__getitem__
,python 会创建一个迭代器,尝试从索引0开始获取元素 - 如果获取失败,则抛出
TypeError
标准序列都实现了 __iter__
方法,所以标准序列都是可迭代对象。如 list,dict,set,tuple。
- 只有实现了
__iter__
方法的对象能通过子类测试issubclass(Object,abc.Itertor)
- 检查对象能否迭代最标准的方法是调用
iter()
函数,因为iter()
会考虑到实现__getitem__
方法的部分可迭代对象。
迭代器
迭代器主要用于从集合中取出元素,那么是什么迭代器呢?
实现了
next
方法的可迭代对象就是迭代器。
next
返回下一个可用的元素,当没有元素时抛出StopIteration
异常。__iter__
,迭代器本身。
到这里应该可以看出「可迭代对象」与 「迭代器」的区别了,就是在于有没有实现next
方法 。
检查对象是不是一个迭代器 :isinstance(object,abc.Iterator)
。
迭代器模式
按需一次获取一个数据项。
迭代器模式的用途有:
- 访问一个聚合对象而无需暴露它的内部结构
- 支持对聚合对象的多种遍历
- 为遍历不同的聚合结构提供一个统一的接口
说了这么多,那么除了标准序列之外,如何自定义一个迭代器呢,看看下面的代码:
class Books:
def __init__(self, books):
self.books = books.split(",")
def __iter__(self):
return BookIterator(self.books)
class BookIterator:
def __init__(self, books):
self.books = books
self.index = 0
def next(self):
try :
book = self.books[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return book
def __iter__(self):
return self
books = Books("python,golang,vue,kubernetes,istio")
print(books)
for book in books :
print(book)
生成器
生成器是一种特殊的迭代器,这种迭代器更加优雅,不需要像上面一样写 __iter__
和 next
方法了,只需要一个 yield
关键字即可。
生成器有两种方法用:
- yield
()
生成
yield
def gen(x) :
for i in range(x) :
yield i * 2
g1 = gen(10)
() 生成器
l1 = [ i * 2 for i in range(10) ]
g1 = (i * 2 for i in range(10))
for i in g1 :
print(i)
print(l1)
- l1 是一个列表推导式
- g1 是一个生成器
- 两者的区别是 g1 生成器采用懒加载的方式,不会一次把数据加载到内存中
生成器的好处不用把数据全部加载到内存中,访问到的时候在计算出来。例如有 100w 的数据集,但是只需要访问前 100 个,是不是生成器就很有用了。
特别说明
上述写法为 python2
的写法,python3
略有不同,python3 中 next 方法对应的为 __next__
,如上面的 Books
例子对应的写法为:
class Books:
def __init__(self, books):
self.books = books.split(",")
def __iter__(self):
return BookIterator(self.books)
class BookIterator:
def __init__(self, books):
self.books = books
self.index = 0
def __next__(self):
try :
book = self.books[self.index]
except IndexError:
raise StopIteration()
self.index += 1
return book
def __iter__(self):
return self
books = Books("python,golang,vue,kubernetes,istio")
print(books)
for book in books :
print(book)
总结
- 任何对象只要实现了
__iter__
方法就是一个可迭代对象- 任何对象只要实现了
__iter__
和next
方法就是一个迭代器- 生成器是一个特殊的迭代器,可以通过
yield
和()
的方式生成- 在数据量大的时候使用会有奇效
来源:oschina
链接:https://my.oschina.net/russellgao/blog/4794236