Day6 python基础6 迭代器和生成器

 

一、列表生成式   

>>> [ i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

  这一句话就相当于

>>> a = []
>>> for i in range(10):
...     a.append(i*2)
...
>>> a
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

 二、生成器 

  通过列表生成式可以直接创建一个列表,在创建的过程中就会一次生成列表中的所有元素,当列表太大时就会占用过大的空间。

  python中,存在一种边循环边计算的机制,称为生成器generator。

  创建生成器的第一种方法:

>>> l = [ i*2 for i in range(10)]
>>> l
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> g = ( i*2 for i in range(10))     #生成器
>>> g
<generator object <genexpr> at 0x0000029B1714C1A8>

  创建生成器与列表生成式的区别在于最外层的[]和()。

  生成器的值只能通过next()方法从头到尾一个一个获得,每调用一次next(g),就计算一个g的值,直到计算的最后一个值,没有更多元素时抛出StopIteration异常。

>>> next(g)
0
>>> next(g)
2
>>> next(g)
4
>>> next(g)
6
>>> next(g)
8
>>> next(g)
10
>>> next(g)
12
>>> next(g)
14
>>> next(g)
16
>>> next(g)
18
>>> next(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

   也可以通过for循环来得到g的值,因为生成器也是可迭代对象。

>>> g = (2*i for i in range(10))
>>> for n in g:
...     print(n)
...
0
2
4
6
8
10
12
14
16
18

  创建生成器的第二种方法,yield关键字。

  示例:斐波那契数列(Fibonacci),除第一个和第二个数外,每一个数都为前两个输之和:

    1,1,2,3,5,8,13,21,34,...

  斐波那契数列无法用列表生成式的形式写出,但可以用函数的形式写出

1 def fib(max):
2     n,a,b = 0,0,1
3     while n<max:
4         print(b)
5         a,b = b,a+b  #相当于t=(b,a+b);a=t[0];b=t[1]
6         n+=1
7 
8 fib(10)
1
1
2
3
5
8
13
21
34
55
Result

  fib函数也是从第一个元素开始,逐个算出后续的元素,若把 print(b) 改为 yield b ,就变成了生成器。 

>>> def fib(max):
...     n,a,b = 0,0,1
...     while n<max:
...             yield b
...             a,b = b,a+b
...             n=n+1
...     return 'done'
...
>>> f = fib(6)
>>> f
<generator object fib at 0x0000029B1714C1A8>
>>> f.__next__()
1
>>> f.__next__()
1
>>> f.__next__()
2
>>> f.__next__()
3
>>> f.__next__()
5
>>> print("do something else")
do something else
>>> f.__next__()
8
>>> f.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration: done
>>>

  在生成器运行过程中,每遇到一次yield,函数会暂停并保留当前所有的运行信息,返回yield,并在下一次执行next()方法时从当前位置继续执行。

  若想得到generator的return语句的返回值,需捕获StopIteration错误。

>>> g = fib(6)
>>> while True:
...     try :
...             x = next(g)
...             print(x)
...     except StopIteration as e:
...             print("generator return:",e.value)
...             break
...
1
1
2
3
5
8
generator return: done

 

 三、迭代器 

  迭代是访问集合元素的一种方式,迭代器对象从集合的第一个元素开始访问,直到被所有元素访问完结束。迭代器只能前进不能后退,且只能从头到尾依次访问。

  迭代器不需要事先生成整个迭代过程中所需的所有元素,而是在迭代到该元素时才生成该元素,而在这之前或之后,元素可以不存在。这一特点使其适合用于遍历一些巨大的或无限的集合。

  迭代器有两个基本方法:next()和iter(),分别用于遍历和生成迭代器。

  可以用于for循环的数据类型有以下几种:

    一类是集合数据类型,如list、tuple、dict、set、str等;

    一类是generator,包括生成器和带yield的generator function。

  这些可以直接作用于for循环的对象统称为可迭代对象:Interable

  可以使用isinstance()判断一个对象是否是Iterable对象:  

>>> from collections import Iterable
>>> isinstance([],Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance('abc',Iterable)
True
>>> isinstance((i*2 for i in range(10)),Iterable)
True
>>> isinstance(100,Iterable)
False

  生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration异常。

  可被next()函数调用并不断返回下一个值的对象称为迭代器Iterator。

  可以使用isinstance()判断一个对象是否是Iterator对象:

>>> isinstance(100,Iterable)
False
>>> from collections import Iterator
>>> isinstance((i for i in range(10)),Iterator)
True
>>> isinstance([],Iterator)
False
>>> isinstance({},Iterator)
False
>>> isinstance('abc',Iterator)
False

  Interator一定是Interable,但Intearble不一定是Iterator。

  python中的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算,而list,dict,str等是直接产生所有数据,故list,dict,str这些数据类型不是Iterator。

  但可以通过iter()方法把list,dict,str等变为Iterator。

>>> isinstance(iter('abc'),Iterator)
True
>>> isinstance(iter([]),Iterator)
True

  python中的for循环的本质就是通过不断调用next()方法实现的,例如:

for x in [1,2,3,4,5]:
    pass

  就相当于:

it = iter([1,2,3,4,5])
while True:
    try:
        x = next(it)
    except StopItreation:
        break

 

posted @ 2018-02-07 23:59  挤成肉夹馍  阅读(156)  评论(0编辑  收藏  举报