Python迭代器Iterator和生成器generator

容器(container)

容器是一种把多个元素组织在一起的数据结构,容器中的元素可以逐个地迭代获取,可以用innot in关键字判断元素是否包含在容器中。通常这类数据结构把所有的元素存储在内存中(也有一些特例,并不是所有的元素都放在内存,比如迭代器和生成器对象)

可迭代对象(iterable)

很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等。但凡是可以返回一个迭代器的对象都可称之为可迭代对象,例如:

>>> x = [1, 2, 3]
>>> y = iter(x)
>>> z = iter(x)
>>> next(y)
1
>>> next(y)
2
>>> next(z)
1
>>> type(x)
<class 'list'>
>>> type(y)
<class 'list_iterator'>

这里x是一个可迭代对象,可迭代对象和容器一样是一种通俗的叫法,并不是指某种具体的数据类型,list是可迭代对象,dict是可迭代对象,set也是可迭代对象。yz是两个独立的迭代器,迭代器内部持有一个状态,该状态用于记录当前迭代所在的位置,以方便下次迭代的时候获取正确的元素。迭代器有一种具体的迭代器类型,比如list_iteratorset_iterator。可迭代对象实现了__iter__方法,该方法返回一个迭代器对象。

迭代器(iterator)

什么是迭代器

迭代器是访问可迭代对象的工具
迭代器是指用iter(obj) 函数返回的对象(实例)
迭代器可以用next(it) 函数获取可迭代对象的数据

任何实现了__iter____next__()(python2中实现next())方法的对象都是迭代器,__iter__返回迭代器自身,__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__方法)。实例变量prevcurr用户维护迭代器内部的状态。每次调用next()方法的时候做两件事:

  1. 为下一次调用next()方法修改状态
  2. 为当前这次调用生成返回结果

生成器(generator)

生成器其实是一种特殊的迭代器,不过这种迭代器更加优雅。它不需要再像上面的类一样写__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 表达式
说明:
    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指定

猜你喜欢

转载自blog.csdn.net/py_1995/article/details/84069107