博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python 基础 列表生成式 生成器
阅读量:4510 次
发布时间:2019-06-08

本文共 5440 字,大约阅读时间需要 18 分钟。

 

列表生成式

列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式

举个例子,要生成list [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]可以用range(1, 11)

>>> range(1, 11)[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

普通循环

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

但是循环太繁琐,而列表生成式则可以用一行语句代替循环生成上面的list:

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

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来

 

看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],我要求你把列表里的每个值加1,你怎么实现?你可能会想到2种方式# 普通青年版>>> a = [1,2,3,4,5,6,7,8]>>>>>> b = []>>>>>> for i in a:b.append( i+1 )...>>> b[2, 3, 4, 5, 6, 7, 8, 9]>>> a = b>>> a[2, 3, 4, 5, 6, 7, 8, 9]>>># 装逼青年版>>> a =[ i+1 for i in range(10) ]>>>>>> a[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 运用列表生成式,可以快速生成list,可以通过一个list推导出另一个list,而代码却十分简洁

 

a = [i for i in b if i]# ==这种方法a = [1,2,3,4,5,6,7,8]if a:    for b in a:        print(b)    # >>> a = [1,2,3,4,5,6,7,8]>>>>>>>>> b = [i for i in a if i]>>> b[1, 2, 3, 4, 5, 6, 7, 8]

 

 

生成器

通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,

从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator

生成器 只有在调用时才会生成相应的数据 列表生成式 用[]  生成器改成()
>>> ( i*2 for i in range(10) )
at 0x0000000002105A98>>>>>>> b = ( i*2 for i in range(10) )>>>>>> for i in b:... print(i)...024681012141618>>>
 
生成器与列表区别 生成器调用才生成数据
>>> c = ( i*2 for i in range(1000)  )>>> c
at 0x0000000002105B48> # 没有生成数据 除非你访问他>>>>>> c = ( i*2 for i in range(1000) )>>> c.__next__() # 生成器用next函数去一个一个去取6>>>>>> c.__next__()8>>>>>> c.__next__()10>>>

 

生成器练习

>>> a = [ i*2 for i in range(10) ]>>> a[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]>>> g = ( i*2 for i in range(50) )>>>>>> g
at 0x000001DF85566BF8>

创建a和g的区别仅在于最外层的[]和(),a是一个list,而g是一个generator。

我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素?

如果要一个一个打印出来,可以通过 __next__()函数获得generator的下一个返回值:

>>> g
at 0x000001DF85566BF8>>>>>>> g.__next__()0>>> g.__next__()2>>> g.__next__()4>>> g.__next__()6>>> g.__next__()8>>> g.__next__()10>>> g.__next__()12>>> g.__next__()14>>> g.__next__()16

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

当然,上面这种不断调用next(g)实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象

>>> g = ( i*2 for i in range(10) )>>>>>> for i in g:...  print(i)...024681012141618>>>

 

所以,我们创建了一个generator后,基本上永远不会调用next(),而是通过for循环来迭代它,并且不需要关心StopIteration的错误。

generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现

 
不能往前走,也不能后退 只记录当前位置 只有一个方法 3.6 __next__() 函数方法。  2.7 next() 函数 优点: 便于循环比较大的数据集合,节省内存
 
 
生成器扩展 斐波拉契

  比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:

 

  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=1 b=2        n = n + 1    return 'done'fib(10)# 赋值语句:a, b = b, a + b # a=1 b=2上面的函数可以输出斐波那契数列的前N个数:11235813213455

 

 

斐波拉契数列1

def fib(max):    n, a, b = 0, 0, 1    while n < max:        #print(b)        yield b        a, b = b, a + b # a=1 b=2        n = n + 1    return 'done'f = fib(10)g = fib(6)while True:    try:        x = next(g)        print('g:', x)    except StopIteration as e:        print('Generator return value:', e.value)        breakprint("===== start loop =====")for i in f:    print(i)

 

仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。

也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:

def fib(max):    n, a, b = 0, 0, 1    while n < max:        #print(b)        yield b        a, b = b, a + b # a=1 b=2        n = n + 1    return 'done'f = fib(50)# 这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:print(f)

 

这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。 而变成generator的函数,在每次调用__next__()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
def fib(max):    n, a, b = 0, 0, 1    while n < max:        #print(b)        yield b        a, b = b, a + b #  a=0 b=1 a=1 b=1 a=1 b=2  a=2 b=3        n = n + 1    return 'done'f = fib(50)# print(f)print(f.__next__())print("==========")print(f.__next__())print("==========")print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())print(f.__next__())# 执行结果1==========1==========23581321345589

在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。

同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:

def fib(max):    n, a, b = 0, 0, 1    while n < max:        #print(b)        yield b        a, b = b, a + b #  a=0 b=1 a=1 b=1 a=1 b=2  a=2 b=3        n = n + 1    return 'done'f = fib(50)print("===== start loop =====")for i in f:    print(i)# 执行结果===== start loop =====1123581321345589

 

通过yield实现在单线程的情况下实现并发运算的效果

通过生成器实现协程并行运算

def consumer(name):    print("%s 准备吃包子啦!" %name)    while True:       baozi = yield       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))c = consumer("mike")c.__next__()b1 = "榨菜"c.send(b1)    # send 给yield传值 并且唤醒

生成器并行

def consumer(name):    print("%s 准备吃包子啦!" %name)    while True:       baozi = yield       print("包子[%s]来了,被[%s]吃了!" %(baozi,name))def producer(name):    c = consumer('A')    c2 = consumer('B')    c.__next__()    c2.__next__()    print("老子开始准备做包子啦!")    for i in range(10):        time.sleep(1)        print("做了2个包子!")        c.send(i)        c2.send(i)producer("ming")

 

 
 

 

转载于:https://www.cnblogs.com/mingerlcm/p/8025076.html

你可能感兴趣的文章
matlab中plot使用方法
查看>>
Haskell 差点儿无痛苦上手指南
查看>>
EJB究竟是什么,真的那么神奇吗??
查看>>
算法学习资料整理
查看>>
怎么对比两个excel文档的数据差异
查看>>
iOS学习笔记08-Quartz2D绘图
查看>>
hive中关键字作为列名的方法
查看>>
创建function实现hive表结果导出到mysql
查看>>
iOS冰与火之歌番外篇 - 在非越狱手机上进行App Hook(转载)
查看>>
pku1018 Communication System
查看>>
nhibernate学习之集合组合依赖
查看>>
系列文章索引
查看>>
绝对震撼 7款HTML5动画应用及源码
查看>>
Objective-C runtime之消息转发机制(三)
查看>>
ios里的KVO模式
查看>>
Xcode Instrument工具 内存泄露
查看>>
使用Python的requests模块编写请求脚本
查看>>
ERP 高级查询(Advanced Query)设计与实现 SQL语句解析成LLBL Gen ORM代码
查看>>
gfs下载文件较大,可以分区域分变量下载
查看>>
用 Mahout 和 Elasticsearch 实现推荐系统
查看>>