13-[函数进阶]-列表生成式,生成器&迭代器
1.列表生成式
Python一种独特的语法,相当于语法糖的存在,可以帮你在某些场合写出比较精简酷炫的代码。但没有它,也不会有太多的影响。
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
- 需求:把a=[0,1,2,3,4,5,6,7,8,9]里面的每个元素+1
# sb版本
>>> b = []
>>> for i in a:b.append(i+1)
>>> a = b # 普通版本
a = [1,3,4,6,7,7,8,9,11] for index,i in enumerate(a):
a[index] +=1
print(a) # 文艺版本
>>> a = map(lambda x:x+1,a)
>>> a
<map object at 0x02861810>
>>> list(a)
[2, 3, 4, 5, 6, 7, 8, 9]
- 装B版本
>>> a = [i+1 for i in range(10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这样的写法就叫做列表生成式
面试真题
看下面代码回答输出的结果是什么?为什么?
result = [lambda x: x + i for i in range(10)]
print(result[0](10))
这是一个结合了变量作用域、列表推导式和匿名函数的题目,较为复杂,比较考验Python基础知识掌握程度。有同学可能会回答10,其实答案是19,并且result[0~9](10)
的结果都是19。
这是因为函数具有调用时才查找变量的特性。在你没调用它之前,它不会保存也不关心它内部变量的具体值。只有等到你调用它的时候,它才逐一去找这些变量的具体值。这里的result[0]被调用的时候,变量i已经循环完毕,变成9了,而不是想象中的动态0-9值。
那如果不想要这样的结果,想要i是循环的值怎么办?不要直接引用上层变量,把变量直接传进来。
result = [lambda x, i=i: x + i for i in range(10)]
print(result[0](10))
2.生成器
想生成一个存放很多数据的列表,但是又不想内存占用太多,最好每次用一个生成一个
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。
- 方法1,只要把一个列表生成式的
[]
改成(),
就创建了一个generator: - 方法2:yield 把函数变成生成器
>>> list1 = [i for i in range(100)]
>>> list1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
>>> li = (i for i in range(100))
>>> li
<generator object <genexpr> at 0x0220C6E8>
- 获取生成器的值:next(li) 和 li.__next__()
>>> li.__next__()
0
>>> li.__next__()
1
>>> li.__next__()
2
>>> next(li)
8
>>> next(li)
9
>>> next(li)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration #每次调用next(g)就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
3.range也是生成器
Python 2.7.12 (default, Jul 1 2016, 15:12:24)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> range(10) # 直接生成list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
>>> xrange(10) #一个生成器,每次调用取值
xrange(10)
>>>
>>> list(xrange(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
range(...)
range(stop) -> list of integers
range(start, stop[, step]) -> list of integers
4.打开文件的f也是生成器
4.斐波那契数列
(1)2B版本
a = 0
b = 1 count = 0
while True:
b,a = a+b,b
print(a)
if b > 200:
break
count += 1
(2)函数版本
def fib(max):
a, b = 0, 1
count = 0
while count < max:
b, a = a+b, b
print(a)
count += 1
return 'done'
fib(10) # 打印10次
5.yield 函数版生成器
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次被next()调用时从上次返回的yield语句处继续执行。
6.生成器send方法
例子:执行到yield时,gen函数作用暂时保存,返回i的值;temp接收下次c.send("python"),send发送过来的值,c.next()等价c.send(None)
def fib(max):
a, b, n = 0, 1, 0
while n < max:
send_msg = yield b
print(send_msg)
a, b = b, a+b
n += 1 f = fib(10)
print(next(f))
f.send('寄个快递')
print(next(f))
In [29]: f.send(None) #第一次相当于f.__next__()
7还可通过yield实现在单线程的情况下实现并发运算的效果
#_*_coding:utf-8_*_
__author__ = 'Alex Li' 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')
c.__next__()
c2.__next__()
print("老子开始准备做包子啦!")
for i in range(10):
time.sleep(1)
print("做了2个包子!")
c.send(i)
c2.send(i) producer("alex") # 通过生成器实现协程并行运算
8.生成器总结
生成器是这样一个函数,它记住上一次返回时在函数体中的位置。对生成器函数的第二次(或第 n 次)调用跳转至该函数中间,而上次调用的所有局部变量都保持不变。
生成器不仅“记住”了它数据状态;生成器还“记住”了它在流控制构造(在命令式编程中,这种构造不只是数据值)中的位置。
生成器的特点:
- 节约内存
- 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
8.迭代器
可以直接作用于for
循环的数据类型:
- 一类是集合数据类型,如
list
、tuple
、dict
、set
、str
等; - 一类是
generator
,包括生成器和带yield
的 generator function。
(1)可迭代对象
直接作用于for
循环的对象统称为可迭代对象:Iterable
。
可以使用isinstance()判断一个对象是否是Iterable对象:
>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance({}, Iterable)
True
>>> isinstance('abc', Iterable)
True
>>> isinstance((x for x in range(10)), Iterable)
True
>>> isinstance(100, Iterable)
False
(2)迭代器:是一种数据流
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
可以使用isinstance()判断一个对象是否是Iterator对象: >>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True
(3)小结
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
- Python3的
for
循环本质上就是通过不断调用next()
函数实现的,例如:
for x in [1, 2, 3, 4, 5]:
pass
实际上完全等价于:
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(it)
except StopIteration:
# 遇到StopIteration就退出循环
break
13-[函数进阶]-列表生成式,生成器&迭代器的更多相关文章
- python协程函数应用 列表生成式 生成器表达式
协程函数应用 列表生成式 生成器表达式 一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._n ...
- Python之旅Day5 列表生成式 生成器 迭代器 装饰器
装饰器 器即函数,装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能 装饰器涉及的知识点= 高阶函数+函数嵌套+闭包 在遵循下面两个原则的前提下为被装饰者新功能 ...
- Py修行路 python基础 (十二) 协程函数应用 列表生成式 生成器表达式
一.知识点整理: 1.可迭代的:对象下有_iter_方法的都是可迭代的对象 迭代器:对象._iter_()得到的结果就是迭代器 迭代器的特性: 迭代器._next_() 取下一个值 优点: 1.提供了 ...
- 列表生成式 生成器 迭代器 yield
列表生成式 格式:通过一个或者若干个在List里边的for构建List而非List外部的for循环 举个例子:计算从1到10整数的平方构成一个List L=[ x*x for x in range(1 ...
- Python全栈之路----函数进阶----列表生成式
列表生成式 现在有个需求,看列表[0,1,2,3,4,5,6,7,8,9],要求你把列表里每个值都加1,你怎么实现?你可能会想到两种方法. 二逼青年版 >>> a = [0,1,2, ...
- Day4 函数、列表生成式、生成器、迭代器
温故而知新: 1. 集合 主要作用: 去重 关系测试, 交集\差集\并集\反向(对称)差集 2. 元组 只读列表,只有count, index 2 个方法 作用:如果一些数据不想被人修改, 可以存成元 ...
- python 基础 4.4 生成式 生成器 迭代器
一.生成式和生成器 列表生成式是python受欢迎的语法之一,通过一句简洁的语法就可以对一组元素进行过滤,还可以对得到的元素进行转换处理. #/usr/bin/python #coding=u ...
- (python函数02)列表生成式
(python函数02)列表生成式 示例代码 num = [i for i in range(1, 10)] print(num) num = [i for i in range(1, 10) ...
- 列表生成式,迭代器&生成器
python3中range(10)就 是迭代器 列表生成式 #列表生成式 a=[0,1,2,3,4,5] b=[] for index,i in enumerate(a): a[index]+1 pr ...
随机推荐
- 如何修改ionic中android程序的包名
默认ionic新建工程的时候指定的Android版本包名是:com.ionicframework.starter:这样固定死包名的话会导致一个问题,多个ionic工程无法正常安装到手机当中,后面安装的 ...
- Oracle EBS 系统仅存在英文的环境
系统管理员 应用服务器 adadmin 编译
- Oracle EBS 导入日记账报错
EM29/EM01 ED01
- 关于sys.dm_exec_requests
我知道SQL Server有很多视图和函数让我来了解SQL Server的运行状态.我还想知道SQL Server上关于来自用户或者应用的活动请求信息.怎么查询这些信息呢? SQL Server的动态 ...
- android-eclips中logcat不显示信息的问题解决
time:2015/11/20 1. logcat窗口不显示问题 解决: 参考[1] 2. logcat中不显示信息 (1)红米手机 (2)解决问题 * 有些文章提到重启eclipse,或者重启手机. ...
- 泛微e-cology和Oracle无法启动的解决方案
最近公司的泛微OA无法访问,Oracle数据库也无法正常启动,尝试了好多方法,终于解决了,先说说基本情况,希望能给碰到同样问题的朋友带来一点帮助. 服务器操作系统:Window s Server 20 ...
- 在 vSphere 5.x/6.0 中配置 Network Dump Collector 服务 (2002954)
vmware KB: https://kb.vmware.com/s/article/2002954?lang=zh_CN 重点配置命令: 使用 vSphere Client 连接到 vCenter ...
- c++ 数组操作(转)
转自 http://www.cnblogs.com/kykuaileren/archive/2011/09/04/2166646.html 一.数组定义和初始化 1: 一维数组初始化: 2: 标准方式 ...
- nodejs API(一)
不要注重版本 URL 官网所在位置:https://nodejs.org/dist/latest-v8.x/docs/api/url.html URL网址解析的好帮手: url有三个可调用的方法:ur ...
- Ubuntu通过Pyenv管理python版本
网上安装使用Pyenv的教程很多,但是实测有很多教程有坑,经过多家比较发现下面的教程可用,内容全面,与大家分享. 首先安装pyenv全家桶 curl -L https://raw.githubuser ...