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 ...
随机推荐
- 【Oracle】PL/SQL Developer使用技巧(持续更新中)
1.关键字自动大写 在sql命令窗口中输入SQL语句时,想要关键字自动大写,引人注目该怎么办呢? 一步设置就可以达成了.点击Tools->Preference->Editor,看到截图中这 ...
- Struts-config.xml配置文件《action-mappings》元素的详解
原文地址:http://blog.163.com/sara1124@126/blog/static/11291097020105125537114/ action-mappings 该元素用于将Act ...
- 通过runtime打印出对象所有属性的值
通过runtime打印出对象所有属性的值 今天给给大家提供的关于NSObject的category,通过runtime打印属性的值,相当有用哦,以后你再也不用每个对象都通过NSLog来逐个打印属性值了 ...
- 计算机中的换行符、回车符、\n、\r、\n\r 怎么区分啊?
'\r'是回车,前者使光标到行首,(carriage return)'\n'是换行,后者使光标下移一格,(line feed) \r 是回车,return\n 是换行,newline对于换行这个动作, ...
- mysql常见问题总结
061 如何删除表? 答案:运行命令 drop table table_name; 062 创建索引 对于查询占主要的应用来说,索引显得尤为重要.很多时候性能问题很简单的就是因为我们忘了添加索引而造成 ...
- java中判断对象中属性值是否为空的函数
public boolean checkObjFieldIsNull(Object obj) throws IllegalAccessException { boolean flag = false; ...
- 【转】爬虫的一般方法、异步、并发与框架scrapy的效率比较
该文非原创文字,文字转载至 jclian91 链接:https://www.cnblogs.com/jclian91/p/9799697.html Python爬虫的N种姿势 问题的由来 ...
- 高可用api接口网络部署方案
我们平时接触的产品都是7*24小时不间断服务,产品中的api接口肯定也是高可用的,下面我向大家分享一下互联网公司api接口高可用的网络部署方案. 我们一般通过http://le.quwenzhe.c ...
- Java 替换空格
题目描述 请实现一个函数,将一个字符串中的空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 解一: 由于最近在学习Head F ...
- 4-1 R语言函数 lapply
#lapply函数 #可以循环处理列表中的每一个元素 #lapply(参数):lapply(列表,函数/函数名,其他参数) #总是返回一个列表 #sapply:简化结果 #结果列表元素长度均为1,返回 ...