列表生成式

列表生成式即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) )
<generator object <genexpr> at 0x0000000002105A98>
>>>
>>> b = ( i*2 for i in range(10) )
>>>
>>> for i in b:
... print(i)
...
0
2
4
6
8
10
12
14
16
18
>>>

生成器与列表区别 生成器调用才生成数据
>>> c = ( i*2 for i in range(1000)  )
>>> c
<generator object <genexpr> 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
<generator object <genexpr> at 0x000001DF85566BF8>

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

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

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

>>> g
<generator object <genexpr> 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)
...
0
2
4
6
8
10
12
14
16
18
>>>

所以,我们创建了一个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个数:
1
1
2
3
5
8
13
21
34
55

斐波拉契数列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)
break print("===== 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 object fib at 0x0000028A4E959AF0>
这里,最难理解的就是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
==========
2
3
5
8
13
21
34
55
89

在上面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 =====
1
1
2
3
5
8
13
21
34
55
89

通过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")
 
												

python 基础 列表生成式 生成器的更多相关文章

  1. python基础——列表生成式

    python基础——列表生成式 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list [1, 2, 3, 4 ...

  2. python基础----列表生成式、生成器表达式

    结论: 1.把列表解析的[]换成()得到的就是生成器表达式 2.列表解析与生成器表达式都是一种便利的编程方式,只不过生成器表达式更节省内存 3.Python不但使用迭代器协议,让for循环变得更加通用 ...

  3. Python基础-列表生成式和生成器表达式

    一.列表生成式(List Comprehension) 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list ...

  4. python 基础 列表生成式

    data = {'a':'abc';'b':'bac','c':'cba'} [v for k,v in data] 结果 ['abc','bca','cba'] 格式 [x for x in  内容 ...

  5. Python之列表生成式、生成器、可迭代对象与迭代器

    本节内容 语法糖的概念 列表生成式 生成器(Generator) 可迭代对象(Iterable) 迭代器(Iterator) Iterable.Iterator与Generator之间的关系 一.语法 ...

  6. 【转】Python之列表生成式、生成器、可迭代对象与迭代器

    [转]Python之列表生成式.生成器.可迭代对象与迭代器 本节内容 语法糖的概念 列表生成式 生成器(Generator) 可迭代对象(Iterable) 迭代器(Iterator) Iterabl ...

  7. python协程函数应用 列表生成式 生成器表达式

    协程函数应用 列表生成式 生成器表达式   一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._n ...

  8. python基础—迭代器、生成器

    python基础-迭代器.生成器 1 迭代器定义 迭代的意思是重复做一些事很多次,就像在循环中做的那样. 只要该对象可以实现__iter__方法,就可以进行迭代. 迭代对象调用__iter__方法会返 ...

  9. python基础——列表推导式

    python基础--列表推导式 1 列表推导式定义 列表推导式能非常简洁的构造一个新列表:只用一条简洁的表达式即可对得到的元素进行转换变形 2 列表推导式语法 基本格式如下: [expr for va ...

随机推荐

  1. MySQL按照汉字拼音首字母排序

    按照汉字的拼音排序,用的比较多是在人名的排序中,按照姓氏的拼音字母,从A到Z排序: 如果存储姓名的字段采用的是GBK字符集,那就好办了,因为GBK内码编码时本身就采用了拼音排序的方法(常用一级汉字37 ...

  2. 这样理解 HTTPS 更容易(Maybe)

    摘要:本文尝试一步步还原HTTPS的设计过程,以理解为什么HTTPS最终会是这副模样.但是这并不代表HTTPS的真实设计过程.在阅读本文时,你可以尝试放下已有的对HTTPS的理解,这样更利于“还原”过 ...

  3. PowerDesigner学习笔记

    首先是概念模型个物理模型的区别,概念模型,即ConceptualDataMode,是没和具体类型的数据库(如SQL Server.MySql)的对应,是一种抽象的,而物理模型是指定了某种具体类型的数据 ...

  4. SALT+HASH撒盐加密

    #region 撒盐加密 string salt = Guid.NewGuid().ToString(); byte[] passwordAndSaltBytes = System.Text.Enco ...

  5. 树莓派上 安装并 运行opencv

    1.先安装依赖项 OpenCV 2.2以后版本需要使用Cmake生成makefile文件,因此需要先安装cmake. sudo apt-get install build-essential sudo ...

  6. 解决一起web 页面被劫持的案例

    现象 江西客户手机端连接wifi打开URL,页面上显示淘宝店铺广告,使用手机移动网络打开正常,其他地区正常. 二. 处理过程 初步分析:3g.club项目使用了CDN,目前只有江西异常,其他地区无异常 ...

  7. Android设计和开发系列第一篇:Notifications通知(Design)

    Design篇 Notifications The notification system allows users to keep informed about relevant and timel ...

  8. 【前端系列】移动前端开发之viewport的深入理解

    在页面上没有设置width所以样式显示有问题,本来选择的响应式模式的320*410结果看到页面的实际宽度确实980px. 本文转载自: 在移动设备上进行网页的重构或开发,首先得搞明白的就是移动设备上的 ...

  9. Android SAX、DOM、Pull解析xml文件剖析与案例讲解

    XML介绍 XML(Extensible Markup Language) 即可扩展标记语言,与HTML一样,都是SGML(Standard Generalized Markup Language,标 ...

  10. vue Element动态设置el-menu导航当前选中项

    1,npm install vuex --save 2,在src下新建vuex文件夹,新建store.js文件: store.js import Vue from 'vue' import Vuex ...