列表生成式:
a=[1,2,3] print a b=[i*2 for i in range(10)] #i循环10次,每一个i的值乘2就是列表中的值。列表生成式 print b >>[1, 2, 3] >>[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
生成器:
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
b=(i*2 for i in range(10)) #将生成列表中的[]转换成(),就是一个生成器。 print b
生成器与列表的区别:
列表在定义的时候,已经在内存中开辟一定空间,而生成器只有在访问元素时才会在内存中开辟空间。
a=[1,2,3] #列表 print a b=(i*2 for i in range(10)) #生成器 print b >>[1, 2, 3] #内存中的值 >><generator object <genexpr> at 0x025048C8> #内存地址
b=(i*2 for i in range(10)) for i in b: #生成器只有在访问元素时才会在内存中开辟空间 print i print b 0 2 4 6 8 10 12 14 16 18 <generator object <genexpr> at 0x02154AF8>
注:生成器不能通过像使用列表那样去使用切片、通过索引访问元素值。
只能通过for循环一个个的取值(只有在调用时才会生成相应的数据),生成器只记住当前的位置,当前的值,前面已经输出的值,生成器不会记得,只有一个_next_()方法3.0,2.7next()
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' fib(10) 1 1 2 3 5 8 13 21 34 55 done
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b '''上面的函数和generator仅一步之遥。要把fib函数变成generator, 只需要把print(b)改为yield b ,yidld 也有return的作用''' a,b = b,a+b n += 1 return 'done' f = fib(6) f data = fib(10) print(data) print(data.__next__()) print(data.__next__()) print("ss") print(data.__next__()) print(data.__next__()) print(data.__next__()) >><generator object fib at 0x104feaaa0> >><generator object fib at 0x101be02b0> >>1 >>1 >>ss >>2 >>3 >>5
还可通过yield实现在单线程的情况下实现并发运算的效果(准确说是协程)
import time def consumer(name): print("%s 准备吃包子啦!" %name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') print c c.next() #这里的c指的是在内存中存放A的内存地址 0x02265490 c2.next() print("老子开始准备做包子啦!") for i in range(5): time.sleep(1) print("做了2个包子!") c.send(i) c2.send(i) producer("小明") <generator object consumer at 0x021D5490> A 准备吃包子啦! B 准备吃包子啦! 老子开始准备做包子啦! 做了2个包子! 包子[0]来了,被[A]吃了! 包子[0]来了,被[B]吃了! 做了2个包子! 包子[1]来了,被[A]吃了! 包子[1]来了,被[B]吃了! 做了2个包子! 包子[2]来了,被[A]吃了! 包子[2]来了,被[B]吃了! 做了2个包子! 包子[3]来了,被[A]吃了! 包子[3]来了,被[B]吃了! 做了2个包子! 包子[4]来了,被[A]吃了! 包子[4]来了,被[B]吃了!
yield 返回当前函数在内存中的地址,
next(),回到yield的执行位置,没有传值的作用。
send(b1) 回到yield的执行位置,可以传值给yield。
迭代器
迭代,顾名思义就是重复做一些事很多次,迭代器是实现了__next__()方法的对象。
能for循环的对象统称为可迭代对象:Iterable,可以使用isinstance()判断一个对象是否是Iterable对象:
from collections import Iteable isinstance([],Iterable) true
可以被next()调用并不断返回下一个值的对象成为迭代器Iterator,查看对象是否是迭代器使用dir()查看是否用next()函数。
生成器就是一个迭代器,
判断是不是一个迭代器:
from collections import Iterator isinstance((i for i in range(5)),Iterator) true
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True