容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用in
, not in
关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)
很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个迭代器的对象都可称之为可迭代对象,例如:
>>> x = [1, 2, 3]
>>> y = iter(x)
>>> z = iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
>>> type(y)
这里x
是一个可迭代对象,可迭代对象和容器一样是一种通俗的叫法,并不是指某种具体的数据类型,list是可迭代对象,dict是可迭代对象,set也是可迭代对象。y
和z
是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。迭代器有一种具体的迭代器类型,比如list_iterator
,set_iterator
。可迭代对象实现了__iter__
方法,该方法返回一个迭代器对象。
迭代器是访问可迭代对象的工具
迭代器是指用iter(obj) 函数返回的对象(实例)
迭代器可以用next(it) 函数获取可迭代对象的数据任何实现了
__iter__
和__next__()
(python2中实现next()
)方法的对象都是迭代器,__iter__
返回迭代器自身,__next__
返回容器中的下一个值
iter(iterable) : 从可迭代对象中返回一个迭代器,iterable 必须是能提供一个迭代器的对象
next(iterator) : 从迭代器iterator中获取下一个记录,如果无法获取下一条记录,则触发StopIteration异常说明:
迭代器只能向前取值,不会后退
用iter函数可以返回一个可迭代对象的迭代器
作用:
迭代器对象能用next函数获取下一个元素.
为了更直观地感受迭代器内部的执行过程,我们自定义一个迭代器,以斐波那契数列为例:
class Fib:
def __init__(self):
self.prev = 0
self.curr = 1
def __iter__(self):
return self
def __next__(self):
value = self.curr
self.curr += self.prev
self.prev = value
return value
>>> f = Fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Fib既是一个可迭代对象(因为它实现了__iter__
方法),又是一个迭代器(因为实现了__next__
方法)。实例变量prev
和curr
用户维护迭代器内部的状态。每次调用next()
方法的时候做两件事:
next()
方法修改状态生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__iter__()
和__next__()
方法了,只需要一个yiled
关键字。 生成器一定是迭代器(反之不成立),因此任何生成器也是以一种懒加载的模式生成值
用生成器来实现斐波那契数列的例子如下:
def fib():
prev, curr = 0, 1
while True:
yield curr
prev, curr = curr, curr + prev
>>> f = fib()
>>> list(islice(f, 0, 10))
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
fib
就是一个普通的python函数,它特殊的地方在于函数体中没有return
关键字,函数的返回值是一个生成器对象。当执行f=fib()
返回的是一个生成器对象,此时函数体中的代码并不会执行,只有显示或隐示地调用next的时候才会真正执行里面的代码。
生成器在Python中是一个非常强大的编程结构,可以用更少地中间变量写流式代码,此外,相比其它容器对象它更能节省内存和CPU,当然它可以用更少的代码来实现相似的功能
生成器是能够动态提供数据的对象,生成器对象也是可迭代对象(实例)
生成器有两种:
1. 生成器函数
2. 生成器表达式
含有yield语句的函数是生成器函数,此函数被调用将返回一个生成器对象
yield 翻译为(产生或生成)
语法:
yield 表达式
说明:
yield 用于 def 函数中,目的是将此函数作用生成器函数使用
yield 用来生成数据,供迭代器的next(it) 函数使用
生成器函数的调用将返回一个生成器对象,生成器对象是一个可迭代对象
在生成器函数调用return 会触发一个StopIteration异常
因此在代码中类似如下代码可以重构优化 :
def something(): result = [] for ... in ...: result.append(x) return result
可以优化为:
def iter_something(): for ... in ...: yield x
下面方法较上面方法更节省CPU和内存
语法:
(表达式 for 变量 in 可迭代对象 [if 真值表达式 ])
说明:
if 子句可以省略
作用:
用推导式的形式创建一个新的生成器
迭代工具函数的作用是生成一个个性化的可迭代对象
zip(iter1[, iter2[, ...]]) 返回一个zip对象,此对象用于生成元组,此元组的个数由最小的可迭代对象决定
enumerate(iterable[, start]) 生成带索引的枚举对象,返回迭代类型为索引-值对(index-value对),默认索引从零开始,也可以用start指定