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)

  通过上面的代码可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算 出后续任意的元素,这种逻辑其实非常类似generator.
  上面的函数与generator仅一步之遥,要把fib函数不安慰generator,只需要把print(b)改为yield b就可以了。
# 生成器演变:
# 斐波拉契: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循环取值时不会出这个错误。

StopIteration: ---done---  这个错误其实就是代码中return的返回结果。
 
但是使用for循环调用时拿不到return的返回值,如果想要拿到返回值,必须要捕获 StopIteration错误,返回值包含在StopIteration的VALUE中
下面就try一下----不详细对try的了解,后续学习中再深入了解。
# 生成器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编辑  收藏  举报

导航