Python函数——列表推导式、生成器与迭代器
列表推导式
产生背景
现在有个需求,看列表[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],要求你把列表里的每个值加1,你怎么实现?
第一种方法:
a = [1,3,4,6,7,7,8,9,11] for ind, val in enumerate(a):
a[ind] += 1
print(a)
第二种方法:
a = [1,3,4,6,7,7,8,9,11]
print(list(map(lambda x: x+1, a)))
列表推导式:
a = [1,3,4,6,7,7,8,9,11]
print([i+1 for i in a])
使用列表推导式可简化代码。用法如下
例一:30以内所有能被3整除的数
print([i for i in list(range(31)) if i % 3 == 0])
#使用if 表达式
例二:30以内所有能被3整除的数的变为平方,否则乘以2
# 使用三元表达式
print([i*i if i % 3 == 0 else i*2 for i in list(range(31))])
练习题:
"""
例1: 过滤掉长度小于3的字符串列表,并将剩下的转换成大写字母 例2: 求(x,y)其中x是0-5之间的偶数,y是0-5之间的奇数组成的元祖列表 例3: 求M中3,6,9组成的列表M = [[1,2,3],[4,5,6],[7,8,9]]
"""
str_li = ['abc', 'cd', 'xy']
print([x.upper() for x in str_li if len(x) >= 3]) print([(x, y) for x in list(range(6)) if x % 2 == 0 for y in list(range(6)) if y % 2 == 1]) M = [[1,2,3],[4,5,6],[7,8,9]]
print([row[2] for row in M])
字典推导式
例一:将一个字典的key和value对调
#
mcase = {'a': 10, 'b': 34}
print({mcase[k]: k for k in mcase})
生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,
如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?
这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
生成器的创建方式
1. 类似于列表生成式()
2. 函数中使用yield
函数有了yield之后
1. 函数调用之后就得到了一个生成器,
2. return 在生成器里,代表生成器的中止,直接报错
3. yield 返回数据 ,并冻结当前的执行过程 。。
类似于列表生成式()创建
L = [x * x for x in range(10)]
gen_L = (x * x for x in range(10)) # 生成器存放计算公式
print(L)
print(gen_L)
print(next(gen_L)) # 取值
print(next(gen_L)) """
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
<generator object <genexpr> at 0x0000000001DFDF10> generator 就是生成器的意思
0
1
"""
generator保存的是算法,每次调用next(g)就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误,使用for循环可以解决异常
g = (x * x for x in range(10))
for n in g:
print(n)
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print('before yield')
yield b # 把函数的执行过程冻结在这一步,并且把b的值 返回给外面的next()
print(b)
a, b = b, a + b
n = n + 1
return 'done' f = fib(15) # turn function into a generator
next(f) # first time call next() next 唤醒冻结的函数执行过程,继续执行,直到遇到下一个yield
next(f) # first time call next() """
before yield
1
before yield
"""
注意a, b = b, a + b 相当于
a, b = 0, 1
a, b = b, a + b
print(a, b)
a, b = 0, 1
t = a
a = b
b = t + b
print(a, b) """
1 1
1 1
"""
函数方式创建
def range2(n):
count = 0
while count < n :
print(count)
stop_flag = yield count #中断并返回
return count
if stop_flag == 'stop':
print('stop iteration...')
break
count += 1
b = range2(5) # 得到生成器
next(b)
next(b)
"""
0
Traceback (most recent call last):
File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/生成器.py", line 53, in <module>
next(b)
StopIteration: 0
"""
生成器常用方法
next() # 唤醒生成器并继续执行
send("stop")
"""
1. 唤醒并继续执行
2. 发送一个信息到生成器内部
注意生成器在刚开始,函数没有执行到yield成为挂起状态时,不能调用send("stop")
只能send('None')相当于next()使函数执行到yield
"""
send使用举例
def range2(n):
count = 0
while count < n:
print('count', count)
count += 1
sign = yield count # return
if sign == 'stop':
print("---sign", sign)
break
print('sin...', sign)
return 3333
new_range = range2(3)
next(new_range)
new_range.send(None)
new_range.send("stop")
"""
count 0
sin... None
count 1
---sign stop
Traceback (most recent call last):
File "C:/Users/jingjing/PycharmProjects/py3Project/路飞/第二模块/函数练习/函数生成器.py", line 22, in <module>
new_range.send("stop")
StopIteration: 3333
"""
生产者与消费者问题
import time def consume(name):
print("%s 准备吃包子啦!" % name)
while True:
y = yield
print("包子[%s]来了,被[%s]吃了!" % (y, name)) def producer(name):
c = consume(name)
next(c) # 函数执行到yield
for i in range(1, 3):
time.sleep(1)
print("做了{}个包子!".format(i))
c.send(i) # 把i传到yield producer('qian')
"""
qian 准备吃包子啦!
做了1个包子!
包子[1]来了,被[qian]吃了!
做了2个包子!
包子[2]来了,被[qian]吃了!
"""
日志记录
def logger(filename):
"""
日志方法
:param filename: log filename
:param channel: 输出的目的地,屏幕(terminal),文件(file),屏幕+文件(both)
:return:
"""
print('start logger')
while True:
msg = yield
print("msg", msg) l = logger('USER.TXT')
l.__next__() l.send('hi')
l.send('hi,file')
计算移动平均值
# 必须先用next再用send
def average():
total=0 #总数
day=0 #天数
average=0 #平均数
while True:
day_num = yield average #average=0
print('average', average)
total += day_num
day += 1
average = total/day
avg=average() #直接返回生成器
next(avg)#激活生成器,avg.send(None),什么都不传的时候send和next的效果一样
print(avg.send(10))
print(avg.send(20))#send 1.传值 2.next
print(avg.send(30))
"""
average 0
10.0
average 10.0
15.0
average 15.0
20.0
"""
带装饰器的计算移动平均值
# 让装饰器去激活
def wrapper(func):
def inner(*args, **kwargs):
print('execute wrapper')
a = func(*args, **kwargs)
next(a)
return a
return inner @wrapper
def average():
total=0 #总数
day=0 #天数
average=0 #平均数
while True:
day_num = yield average #average=0
print('average', average)
total += day_num
day += 1
average = total/day avg = average()
print(avg.send(10))
print(avg.send(20))#send 1.传值 2.next
print(avg.send(30))
"""
execute wrapper
average 0
10.0
average 10.0
15.0
average 15.0
20.0
"""
yield from
def gen1():
for c in 'AB':
yield c
for i in range(3):
yield i
print(gen1())
print(list(gen1())) def gen2():
yield from 'AB' # 相当于 for c in 'AB': yield c
yield from range(3)
print(gen2())
print(list(gen2()))
处理异常
def fib(max):
n, a, b = 0, 0, 1
while n < max:
print('before yield')
yield b # 把函数的执行过程冻结在这一步,并且把b的值 返回给外面的next()
a, b = b, a + b
n = n + 1
return 'done' g = fib(6)
while True:
try:
x = next(g)
print('g:', x)
except StopIteration as e:
print('Generator return value:', e.value)
break
生成器小结
生成器的创建方式
1. 类似于列表生成式()
2. 函数中使用yield
优点:节省内存空间
函数有了yield之后
1. 函数调用之后就得到了一个生成器,
2. return 在生成器里,代表生成器的中止,直接报错
注意
python3 range相当于python2 xrange 生成器
python2 range相当于list
yield vs return
return 返回并中止function
yield 返回数据 ,并冻结当前的执行过程 。。
生成器常用方法
1.next()
2.send("stop")
"""
1. 唤醒并继续执行
2. 发送一个信息到生成器内部
注意生成器在刚开始,函数没有执行到yield成为挂起状态时,不能调用send("stop")
只能send('None')相当于next()使函数执行到yield
"""
迭代器
可迭代对象与迭代器
迭代:可以将某个数据集内的数据“一个挨着一个的取出来”,就叫做迭代。就像for循环一样取值。
可迭代协议:可以被迭代要满足要求的就叫做可迭代协议。内部实现了__iter__方法
iterable:可迭代的------对应的标志
字符串、列表、元组、字典、集合都可以被for循环,说明他们都是可迭代的。
可以使用isinstance()判断一个对象是否是Iterable对象:
from collections import Iterable
print(isinstance([], Iterable))
print(isinstance(123, Iterable))
print(isinstance('', Iterable))
# """
# True
# False
# True
# """
而生成器不但可以作用于for循环,还可以被next()函数不断调用并返回下一个值,直到最后抛出StopIteration错误表示无法继续返回下一个值了
迭代器协议:内部实现了__iter__,__next__方法。
迭代器的优点:如果用了迭代器,节约内存,方便操作,生成器是一种迭代器(Iterator)。
可迭代和迭代器的相同点:都可以用for循环
可迭代和迭代器的不同点:就是迭代器内部多实现了一个__next__方法
判断迭代器和可迭代的方法:
第一种:判断内部是不是实现了__next__方法
print('__next__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__
print('__iter__' in dir(range(12))) #查看'__next__'是不是在range()方法执行之后内部是否有__next__
第二种:
Iterable 判断是不是可迭代对象
Iterator 判断是不是迭代器
from collections import Iterable
from collections import Iterator #比如给一个字符串
s='abc'
print(isinstance(s,Iterable))#isinstance判断类型的
print(isinstance(s,Iterator))
判断range函数和map函数

深入了解Iterator对象
生成器都是Iterator对象,但list、dict、str虽然是Iterable,却不是Iterator。
把list、dict、str等Iterable变成Iterator可以使用iter()函数:

你可能会问,为什么list、dict、str等数据类型不是Iterator?
这是因为Python的Iterator对象表示的是一个数据流,Iterator对象可以被next()函数调用并不断返回下一个数据,
直到没有数据时抛出StopIteration错误。可以把这个数据流看做是一个有序序列,但我们却不能提前知道序列的长度,
只能不断通过next()函数实现按需计算下一个数据,所以Iterator的计算是惰性的,只有在需要返回下一个数据时它才会计算。
Iterator甚至可以表示一个无限大的数据流,例如全体自然数。而使用list是永远不可能存储全体自然数的。
迭代器小结
凡是可作用于for循环的对象都是Iterable类型;
凡是可作用于next()函数的对象都是Iterator类型,它们表示一个惰性计算的序列;
集合数据类型如list、dict、str等是Iterable但不是Iterator,不过可以通过iter()函数获得一个Iterator对象。
Python3的for循环本质上就是通过不断调用next()函数实现的,例如:
for x in [1, 2, 3, 4, 5]:
pass
等价于
# 首先获得Iterator对象:
iter_object = iter([1, 2, 3, 4, 5])
# 循环:
while True:
try:
# 获得下一个值:
x = next(iter_object)
except StopIteration:
# 遇到StopIteration就退出循环
break
Python函数——列表推导式、生成器与迭代器的更多相关文章
- Python的高级特性2:列表推导式,生成器与迭代器
一.列表推导式 1.列表推导式是颇具python风格的一种写法.这种写法除了高效,也更简短. In [23]: {i:el for i,el in enumerate(["one" ...
- python之生成器(~函数,列表推导式,生成器表达式)
一.生成器 概念:生成器的是实质就是迭代器 1.生成器的贴点和迭代器一样,取值方式也和迭代器一样. 2.生成器一般由生成器函数或者声称其表达式来创建,生成器其实就是手写的迭代器. 3.在python中 ...
- python 3列表推导式的的一点理解!
python 3列表推导式的的一点理解! Python的列表推导式对于新手来说一般都难以理解,简单看个例子: [x * x for x in range(1,100)] 上面是一个很简单的列表推导式, ...
- python基础——列表推导式
python基础--列表推导式 1 列表推导式定义 列表推导式能非常简洁的构造一个新列表:只用一条简洁的表达式即可对得到的元素进行转换变形 2 列表推导式语法 基本格式如下: [expr for va ...
- Python基础-列表推导式
python中列表推导式有三种数据类型可用:列表,字典,集合 列表推导式书写形式: [表达式 for 变量 in 列表] 或者 [表达式 for 变量 in 列表 if 条件] 1,列表推导式 ...
- Python入门之三元表达式\列表推导式\生成器表达式\递归匿名函数\内置函数
本章目录: 一.三元表达式.列表推导式.生成器表达式 二.递归调用和二分法 三.匿名函数 四.内置函数 ================================================ ...
- python 全栈开发,Day14(列表推导式,生成器表达式,内置函数)
一.列表生成式 生成1-100的列表 li = [] for i in range(1,101): li.append(i) print(li) 执行输出: [1,2,3...] 生成python1期 ...
- python基础之生成器,生成器函数,列表推导式
内容梗概: 1. 生成器和生成器函数. 2. 列表推导式. 1.生成器函数1.1 生成器函数. 就是把return换成yield def gen(): print("爽歪歪") y ...
- Python基础-列表推导式、匿名函数、os/sys/time/datetime/pymysql/xlwt/hashlib模块
列表推导式 [表达式 for 变量 in range(n) if 条件] 等效于 for 变量 in in range(n): if 条件: 表达式 优点:书写方便,缺点:不易读 注意:用的是方括号 ...
随机推荐
- SpringJDBC中jdbcTemplate 的使用
一:定义 SpringJDBC是spring官方提供的一个持久层框架,对JDBC进行了封装,提供了一个JDBCTemplated对象简化JDBC的开发.但Spring本身不是一个orm框架,与hibe ...
- Pandas数据的去重,替换和离散化,异常值的检测
数据转换 移除重复数据 import pandas as pd import numpy as np from pandas import Series data = pd.DataFrame( {' ...
- Jenkins之定时任务
H的用法: H 10 * * * ,这里H不是小时的意思,符号H(代表“Hash”,后面用“散列”代替) 符号H 在一定范围内可被认为是一个随机值,但实际上它是任务名称的一个散列而不是随机函数,每个 ...
- SQL Server 定价及授权方式
https://www.microsoft.com/zh-cn/sql-server/sql-server-2017-pricing http://www.360doc.com/content/15/ ...
- input text 只能输入数字
添加 onkeyup="value=value.replace(/[^\d]/g,'')"
- [leetcode]57. Insert Interval插入区间
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...
- 自定义View(四) ViewGroup 动态添加变长Tag标签 支持自动换行
欲实现如下效果: 思路很简单就2步: 1.测量出ViewGroup的大小 2.找出子View的位置 若要实现动态添加标签view,就要实现ViewGroup的onMeasure().onLayout( ...
- pip 国内源 配置
pip 国内源 配置 2017年12月09日 16:05:20 阅读数:183 最近使用 pip 安装包,动辄十几 k 甚至几 k 的下载速度,确实让人安装的时候心情十分不好.所以还是要给 pip 换 ...
- 【.Net】 大文件可使用的文本分组统计工具(附带源码,原创)
本工具可实现的效果: 1.读取大文件(大于1GB) 2.根据分隔符分割后的列分组 3.速度快. 4.处理过程中,可以随时停止处理,操作不卡死. 5.有对当前内存的实时监测,避免过多占用内存,影响系统运 ...
- 万能的一句话 json
String str1 = new JavaScriptSerializer().Serialize(meetapply1);//meetapply1==object T