迭代器和生成器
Posted brace2011
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了迭代器和生成器相关的知识,希望对你有一定的参考价值。
迭代器和生成器;
>>> a = [1,2,3,4]
>>> a
[1, 2, 3, 4]
列表生成式:
>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
生成器:
通过列表生成式就可以直接创建一个列表,但是受内存的限制,列表容量肯定是有限的,
常规的列表的有些元素用不上却占用了不少空间。
在python中,一边循环一边计算的机制,叫生成器:generator
创建生成器的方式:
1. 将生成式的[]改为(),就成为了生成器;
>>> (i*2 for i in range(10))
<generator object <genexpr> at 0x03811EA0>
>>> for n in (i*2 for i in range(10)):
... print(n)
...
0
2
4
6
8
10
12
14
16
18
>>> a = [ i*2 for i in range(10000000) ] #耗时长;
>>> b = ( i*2 for i in range(10000000) ) #很快,只是生成一个算法;
>>>
>>> a[1000]
2000 #元素是已经生成好的
>>> b[1000] #元素还没生成,所以出错;
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ‘generator‘ object is not subscriptable
>>>
生成器只有在调用时才会生成相应的数据;
生成器的元素只能一个一个的来取。可以用next来取,
只记住当前的位置;
只有一个__next__方法,Python2.7为next()
>>> b.__next__()
0
>>> b.__next__()
2
>>> b.__next__()
4
>>> b.__next__()
6
>>>
生成器非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现,可以用函数来实现;
斐波拉契列:
1,1,2,3,5,8,13,21,34,.........
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a+b
n += 1
return "done"
fib(10)
输出:
1
1
2
3
5
8
13
21
34
55
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #改为yield后就成了生成器
a, b = b, a+b
n += 1
return "done"
print(fib(10))
for n in fib(10):
print(n)
输出:
<generator object fib at 0x02C1F150>
1
1
2
3
5
8
13
21
34
55
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
return "done"
f = fib(10)
f.__next__()
f.__next__()
print("========")
f.__next__()
print("========")
print(f.__next__())
print(f.__next__())
print("+++++++++")
for n in f:
print(f.__next__())
输出:
========
========
3
5
+++++++++
13
34
Traceback (most recent call last):
File "D:/Python3/python_project/Project_1/Day-06-17/genrator.py", line 33, in <module>
print(f.__next__())
StopIteration: done
Process finished with exit code 1
# 捕捉异常:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
return "done"
f = fib(10) #仅仅是生成生成器
f.__next__() #初始化并生成一个数据
f.__next__()
print("========")
f.__next__() #产生第三数据
print("========")
print(f.__next__())
print(f.__next__()) #产生第五数据,退出不妨碍往后产生数据
print("+++++++++")
try:
for n in f:
print(f.__next__()) #产生第六数据
except StopIteration : #取完后就会溢出,异常被捕获而中断;
print("done!")
输出:
========
========
3
5
+++++++++
13
34
done!
>>> a = [1,2,3,4]
>>> a
[1, 2, 3, 4]
列表生成式:
>>> [i*2 for i in range(10)]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
生成器:
通过列表生成式就可以直接创建一个列表,但是受内存的限制,列表容量肯定是有限的,
常规的列表的有些元素用不上却占用了不少空间。
在python中,一边循环一边计算的机制,叫生成器:generator
创建生成器的方式:
1. 将生成式的[]改为(),就成为了生成器;
>>> (i*2 for i in range(10))
<generator object <genexpr> at 0x03811EA0>
>>> for n in (i*2 for i in range(10)):
... print(n)
...
0
2
4
6
8
10
12
14
16
18
>>> a = [ i*2 for i in range(10000000) ] #耗时长;
>>> b = ( i*2 for i in range(10000000) ) #很快,只是生成一个算法;
>>>
>>> a[1000]
2000 #元素是已经生成好的
>>> b[1000] #元素还没生成,所以出错;
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ‘generator‘ object is not subscriptable
>>>
生成器只有在调用时才会生成相应的数据;
生成器的元素只能一个一个的来取。可以用next来取,
只记住当前的位置;
只有一个__next__方法,Python2.7为next()
>>> b.__next__()
0
>>> b.__next__()
2
>>> b.__next__()
4
>>> b.__next__()
6
>>>
生成器非常强大,如果推算的算法比较复杂,用类似列表生成式的for循环无法实现,可以用函数来实现;
斐波拉契列:
1,1,2,3,5,8,13,21,34,.........
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print(b)
a, b = b, a+b
n += 1
return "done"
fib(10)
输出:
1
1
2
3
5
8
13
21
34
55
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b #改为yield后就成了生成器
a, b = b, a+b
n += 1
return "done"
print(fib(10))
for n in fib(10):
print(n)
输出:
<generator object fib at 0x02C1F150>
1
1
2
3
5
8
13
21
34
55
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
return "done"
f = fib(10)
f.__next__()
f.__next__()
print("========")
f.__next__()
print("========")
print(f.__next__())
print(f.__next__())
print("+++++++++")
for n in f:
print(f.__next__())
输出:
========
========
3
5
+++++++++
13
34
Traceback (most recent call last):
File "D:/Python3/python_project/Project_1/Day-06-17/genrator.py", line 33, in <module>
print(f.__next__())
StopIteration: done
Process finished with exit code 1
# 捕捉异常:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a+b
n += 1
return "done"
f = fib(10) #仅仅是生成生成器
f.__next__() #初始化并生成一个数据
f.__next__()
print("========")
f.__next__() #产生第三数据
print("========")
print(f.__next__())
print(f.__next__()) #产生第五数据,退出不妨碍往后产生数据
print("+++++++++")
try:
for n in f:
print(f.__next__()) #产生第六数据
except StopIteration : #取完后就会溢出,异常被捕获而中断;
print("done!")
输出:
========
========
3
5
+++++++++
13
34
done!
#########################################################
案例:通过yield实现在单线程的的情况下实现并发预算效果,即所谓的多线程效果,也称为协程
import time
def consumer(name):
print("%s 准备吃包子了!"% name)
while True:
baozi = yield
print("包子[%s]来了,一半被[%s]吃了"% (baozi, name))
def producer(name):
c1 = consumer("A") #只是把函数变成了生成器,其他什么也没做
c2 = consumer("B")
c1.__next__() #初始化准备吃包子,此时生成器开始执行,走到yield开始卡住了(等待生成包子),因为此时生成器还没生成数据。
c2.__next__()
print("%s开始准备做包子了!"% name)
for i in range(5):
time.sleep(1)
print("%s 做了2个包子"% name)
c1.send("韭菜") #给生成器生成一个数据,
c2.send("奶黄")
producer("Lucy")
输出:
A 准备吃包子了!
B 准备吃包子了!
Lucy开始准备做包子了!
Lucy做了2个包子
包子[韭菜]来了,被[A]吃了
包子[奶黄]来了,被[B]吃了
Lucy做了2个包子
包子[韭菜]来了,被[A]吃了
包子[奶黄]来了,被[B]吃了
Lucy做了2个包子
包子[韭菜]来了,被[A]吃了
包子[奶黄]来了,被[B]吃了
Lucy做了2个包子
包子[韭菜]来了,被[A]吃了
包子[奶黄]来了,被[B]吃了
Lucy做了2个包子
包子[韭菜]来了,被[A]吃了
包子[奶黄]来了,被[B]吃了
迭代器:
可以直接作用于for循环的数据类型有以下几种:
一类:集合数据类型,如:list,tuple,dict,set,str等
一类:generator 包括生成器和带yield的generation function
这些可以直接作用于for循环的对象统称为可迭代对象,Iterable
可以使用isinstance()判断一个对象是否是Iterable
>>> from collections import Iterable
>>> isinstance("abc",Iterable)
True
>>> isinstance([1,2,3,4],Iterable)
True
>>> isinstance({},Iterable)
True
>>> isinstance(10,Iterable)
False
>>>
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下个值,直到最后抛出异常
可以被next()函数调用并不断返回下一个值的对象统称为迭代器:Iterator
>>> from collections import Iterator
>>> isinstance([1,2,3,4],Iterator)
False
>>>
>>> isinstance((x *2 for x in range(10)),Iterator)
True
>>>
生成器都是Iterator 对象,但list,dict,str等虽然是Iterable,却不是Iterator
把list,dict,str等Iterable变成Iterator迭代器,可以使用iter()函数;
>>> isinstance(iter([1,2,3,4]),Iterator)
True
>>> x = iter([1,2,3,4])
>>> x.__next__()
1
>>> x.__next__()
2
>>> x.__next__()
3
>>> x.__next__()
4
Python的Itertor对象表示的是一个数据流,可以被next()函数调用并不停的返回下一个数据,直到没有数据时抛出StopIteration异常
可以把这个数据流看着是一个有序序列,但我们却不知道序列的长度,只能不断通过next()函数实现按需计算下一个数据。
所以Iteratorhi的计算是惰性的,只有在需要返回下一个数据时才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数,但使用list是永远不可能存储全体自然数的(五穷尽的数据)。
it = iter([1,2,3,4,5,6,6,6])
while True:
try:
x = next(it)
print(x)
except StopIteration:
break
输出:
1
2
3
4
5
6
6
6
以上是关于迭代器和生成器的主要内容,如果未能解决你的问题,请参考以下文章