day1-3生成器
一、列表生成式
# 列表生成式:
#以前所学列表
a = [1,2,3]
print("a的值>>>",a)
#列表生成式
b = [i*2 for i in range(10)]
print("b的值>>>",b)
上面两段代码执行结果:
以前所学列表与列表生成式的区别:
列表生成式可以动态变化,可以动态的做一些改变,而以前所学的列表就已经写死了。
为了达到列表生成式的效果,按照以前所学的可以做如下处理:
#按照以前所学达到列表生成式的效果:可以动态的对列表做一些操作
c=[]
for i in range(10):
c.append(i*2)
print("c的值>>>",c)
执行结果如下:
小结:
从上面可以看出列表生成式一条代码就能实现功能,而后面的需要3条代码才能实现,列表生成式简洁。
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了.
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
如:
#列表生成式
a = [ i*2 for i in range(10) ]
print("列表生成式a的结果>>>",a)
#生成器,将[]换为()
b = ( i*2 for i in range(10) )
print("生成器b的结果>>>",b)
for i in b:
print("循环b>>>",i)
执行结果如下:
>>> a = [ i*2 for i in range(100000000) ]
>>>
>>>
>>>
>>> len(a)
100000000
#创建a列表时中间会停顿十几秒钟,存储到硬盘中,
>>> b = ( i*2 for i in range(100000000) )
#创建b时很快就执行完了,只有通过for循环调用时才会花一段时间,创建b时存到硬盘中的数据很小,节约了空间,只有调用才占空间。
>>> for i in b:
... print(b)
上面通过ctrl +c暂停。
生成器不支持列表切片a[1]这样的方式去取它
取出生成器的值有两个方法:
1、for循环 (从头取到尾) 上面已经介绍
2、_ _next_ _() 下面即将介绍
生成器只有在调用时才会生成相应的数据,调用那次就产生那次的数据。
生成器_ _next_ _()方法去取:
>>> b.__next__()
52900
>>> b.__next__()
53361
>>> b.__next__()
53824
>>> b.__next__()
54289
>>> b.__next__()
54756
上面其实是两个下划线,连着就是上面那样的。
生成器特点:
生成器怎么省内存:只保留当前一个值,不能往回返,只能一步一步往后走,只有一个方法:_ _next_ _(),在2.7里是next()
上面这种不断调用next()
实在是太变态了,正确的方法是使用for
循环,因为generator也是可迭代对象:
所以,我们创建了一个generator后,基本上永远不会调用next()
,而是通过for
循环来迭代它,并且不需要关心StopIteration
的错误。
生成器如何生成:
带你做一个生成器。
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for
循环无法实现的时候,还可以用函数来实现
著名的斐波拉契数列(Fibonacci):除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, ...
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
例:使用函数实现斐波拉契数列:
# 斐波拉契: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 #相当于下个a=b b=a+b
#n=0 打印b0=1 ,然后 a1=b0=1 b1=0+1 ,然后n+1=1,打印b1=1,go> a2=b1=1 b2=a1+b1=1+1=2,
#n+1=2 打印b2=2,go> a3=b2=2,b3=a2+b2=1+2=3, n+1=3时依次类推
n +=1
return "done" #return是异常显示的消息
fib(10)
执行结果:
可以详细解析一下函数执行过程:
首先定义:n,a,b = 0 , 0 , 1 可以理解:n0=0 ,a0=0,b0=1
n=0 :
print(b) ----- 理解: 打印b0=1 ,
a,b = b,a+b ----理解: a1=b0=1 b1=0+1 ,
n+1=1:
print(b) ----- 理解: 打印b1=1,
a,b = b,a+b ----理解: a2=b1=1 b2=a1+b1=1+1=2,
n+1=2:
print(b) ----- 理解: 打印b2=2
a,b = b,a+b ----理解: a3=b2=2,b3=a2+b2=1+2=3,
n+1=3:时依次类推......
二、生成器(generator)
# 生成器演变:
# 斐波拉契:1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max):
n,a,b = 0 , 0 , 1
while n < max:
# print(b)
yield b
a,b = b,a+b #相当于下个a=b b=a+b
#n=0 打印b0=1 ,然后 a1=b0=1 b1=0+1 ,然后n+1=1,打印b1=1,go> a2=b1=1 b2=a1+b1=1+1=2,
#n+1=2 打印b2=2,go> a3=b2=2,b3=a2+b2=1+2=3, n+1=3时依次类推
n +=1
return "done" #return是异常显示的消息
f=fib(10)
print(f) #<generator object fib at 0x0000025B15E4B258> 表示已经是生成器了。然后调用一下
print(f.__next__())
print("-----分割线------") #有了生成器随时都可以退出函数调用其他程序
print(f.__next__()) #调用完其他程序然后继续调用函数,这样反复多少次都可以
print("-----分割线------") #有了生成器随时都可以退出函数调用其他程序
print(f.__next__()) #调用完其他程序然后继续调用函数,这样反复多少次都可以
执行结果:
如果通过.__next__()方法向下取每个值,超出了这个值后,就会出错。用for循环取值时不会出这个错误。
# 生成器try一下。
# 斐波拉契:1, 1, 2, 3, 5, 8, 13, 21, 34, ...
def fib(max):
n,a,b = 0 , 0 , 1
while n < max:
# print(b)
yield b
a,b = b,a+b #相当于下个a=b b=a+b
#n=0 打印b0=1 ,然后 a1=b0=1 b1=0+1 ,然后n+1=1,打印b1=1,go> a2=b1=1 b2=a1+b1=1+1=2,
#n+1=2 打印b2=2,go> a3=b2=2,b3=a2+b2=1+2=3, n+1=3时依次类推
n +=1
return "—done—" #return是异常显示的消息
# try一下
f=fib(10)
while True:
try:
x = next(f)
print("f:",x)
except StopIteration as e:
print("Generator return value:",e.value)
break
执行结果:
posted on 2017-07-10 22:56 aptech2017 阅读(62) 评论(0) 编辑 收藏 举报