python列表生成式与列表生成器的使用


Posted in Python onFebruary 23, 2018

列表生成式:会将所有的结果全部计算出来,把结果存放到内存中,如果列表中数据比较多,就会占用过多的内存空间,可能会导致MemoryError内存错误或者导致程序在运行时出现卡顿的情况

列表生成器:会创建一个列表生成器对象,不会一次性的把所有结果都计算出来,如果需要获取数据,可以使用next()函数来获取,但是需要注意,一旦next()函数获取不到数据,会导致出现StopIteration异常错误,可以使用for循环遍历列表生成器,获取所有数据

需要视情况而定,如果数据量比较大,推荐使用生成器

 python2.7中就是range(生成式) 和 xrange(生成器)的区别

列表生成式是快速生成一个列表的一些公式

在列表中存放0~100的数:

普通的列表生成:

numbers=[] 
for x in range(0,101): 
  numbers.append(x) 
print(numbers)

用列表生成式生成列表:[要放入列表的数据    简单的表达式1   表达式2]

#x for x in range(0,101) for循环遍历出来的值,放入列表中 
numbers=[x for x in range(0,101)] 
print(numbers)

列表中存放0~100的偶数:

普通方法生成列表:

for x in range(0,101): 
  if x%2==0: 
    numbers.append(x) 
print(numbers)

用列表生成式生成列表:

#for循环遍历0~101的数字,如果数字对2取余==0,表示是偶数,x放在列表中 
numbers=[x for x in range(0,101)if x%2==0] 
print(numbers)

找出列表list1=['asd','adf','dafg','acbo']带有a的字符

普通写法:

rs_list=[] 
for s in list1: 
  if 'a' in s: 
    rs_list.append(s) 
print(rs_list)

列表生成式:

list2=[x for x in list1 if 'a' in x]

列表生成式支持双层for循环

list3=[x*y for x in range(0,10) for y in range(20)] 
print(list3)

生成器构造实例

# 使用类似列表生成式的方式构造生成器
g1 = (2*n + 1 for n in range(3, 6))

# 使用包含yield的函数构造生成器
def my_range(start, end):
  for n in range(start, end):
    yield 2*n + 1

g2 = my_range(3, 6)
print(type(g1))
print(type(g2))

输出结果:

<class 'generator'>
<class 'generator'>

生成器的调用方式

  1. 要调用生成器产生新的元素,有两种方式:
  2. 调用内置的next()方法
  3. 使用循环对生成器对象进行遍历(推荐)
  4. 调用生成器对象的send()方法

实例1:使用next()方法遍历生成器

print(next(g1))
print(next(g1))
print(next(g1))
print(next(g1))

输出结果:

7
9
11
Traceback (most recent call last):
  File "***/generator.py", line 26, in <module>
    print(next(g1))
StopIteration

print(next(g2))
print(next(g2))
print(next(g2))
print(next(g2))

输出结果:

7
9
11
Traceback (most recent call last):
  File "***/generator.py", line 31, in <module>
    print(next(g2))
StopIteration

可见,使用next()方法遍历生成器时,最后是以抛出一个StopIeration异常终止。

实例2:使用循环遍历生成器

for x in g1:
  print(x)

for x in g2:
  print(x)

两个循环的输出结果是一样的:

7
9
11

可见,使用循环遍历生成器时比较简洁,且最后不会抛出一个StopIeration异常。因此使用循环的方式遍历生成器的方式才是被推荐的。

需要说明的是:如果生成器函数有返回值,要获取该返回值的话,只能通过在一个while循环中不断的next(),最后通过捕获StopIteration异常

实例3:调用生成器对象的send()方法

def my_range(start, end):
  for n in range(start, end):
    ret = yield 2*n + 1
    print(ret)

g3 = my_range(3, 6)
print(g3.send(None))
print(g3.send('hello01'))
print(g3.send('hello02'))

输出结果:

7
hello01
9
hello02
11

print(next(g3))
print(next(g3))
print(next(g3))

输出结果:

7
None
9
None
11

结论:

  1. next()会调用yield,但不给它传值
  2. send()会调用yield,也会给它传值(该值将成为当前yield表达式的结果值)

需要注意的是:第一次调用生成器的send()方法时,参数只能为None,否则会抛出异常。当然也可以在调用send()方法之前先调用一次next()方法,目的是让生成器先进入yield表达式。

生成器与列表生成式对比

既然通过列表生成式就可以直接创建一个新的list,那么为什么还要有生成器存在呢?

因为列表生成式是直接创建一个新的list,它会一次性地把所有数据都存放到内存中,这会存在以下几个问题:

  1. 内存容量有限,因此列表容量是有限的;
  2. 当列表中的数据量很大时,会占用大量的内存空间,如果我们仅仅需要访问前面有限个元素时,就会造成内存资源的极大浪费;
  3. 当数据量很大时,列表生成式的返回时间会很慢;

而生成器中的元素是按照指定的算法推算出来的,只有调用时才生成相应的数据。这样就不必一次性地把所有数据都生成,从而节省了大量的内存空间,这使得其生成的元素个数几乎是没有限制的,并且操作的返回时间也是非常快速的(仅仅是创建一个变量而已)。

我们可以做个试验:对比一下生成一个1000万个数字的列表,分别看下用列表生成式和生成器时返回结果的时间和所占内存空间的大小:

import time
import sys

time_start = time.time()
g1 = [x for x in range(10000000)]
time_end = time.time()
print('列表生成式返回结果花费的时间: %s' % (time_end - time_start))
print('列表生成式返回结果占用内存大小:%s' % sys.getsizeof(g1))

def my_range(start, end):
  for x in range(start, end):
    yield x

time_start = time.time()
g2 = my_range(0, 10000000)
time_end = time.time()
print('生成器返回结果花费的时间: %s' % (time_end - time_start))
print('生成器返回结果占用内存大小:%s' % sys.getsizeof(g2))

输出结果:

列表生成式返回结果花费的时间: 0.8215489387512207
列表生成式返回结果占用内存大小:81528056
生成器返回结果花费的时间: 0.0
生成器返回结果占用内存大小:88

可见,生成器返回结果的时间几乎为0,结果所占内存空间的大小相对于列表生成器来说也要小的多。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
利用Django框架中select_related和prefetch_related函数对数据库查询优化
Apr 01 Python
Python实现GUI学生信息管理系统
Apr 05 Python
详解python的ORM中Pony用法
Feb 09 Python
异步任务队列Celery在Django中的使用方法
Jun 07 Python
[原创]Python入门教程2. 字符串基本操作【运算、格式化输出、常用函数】
Oct 29 Python
对Python3使运行暂停的方法详解
Feb 18 Python
python2和python3在处理字符串上的区别详解
May 29 Python
详解PyTorch手写数字识别(MNIST数据集)
Aug 16 Python
Python 网络编程之UDP发送接收数据功能示例【基于socket套接字】
Oct 11 Python
Python读取VOC中的xml目标框实例
Mar 10 Python
使用Python绘制台风轨迹图的示例代码
Sep 21 Python
Python可视化工具如何实现动态图表
Oct 23 Python
1分钟快速生成用于网页内容提取的xslt
Feb 23 #Python
python使用xslt提取网页数据的方法
Feb 23 #Python
Python爬虫使用Selenium+PhantomJS抓取Ajax和动态HTML内容
Feb 23 #Python
python爬虫获取多页天涯帖子
Feb 23 #Python
Python即时网络爬虫项目启动说明详解
Feb 23 #Python
Python爬豆瓣电影实例
Feb 23 #Python
Python抓取聚划算商品分析页面获取商品信息并以XML格式保存到本地
Feb 23 #Python
You might like
PHP命名空间(Namespace)简明教程
2014/06/11 PHP
深入浅析php中sprintf与printf函数的用法及区别
2016/01/08 PHP
46 个非常有用的 PHP 代码片段
2016/02/16 PHP
PHP基于GD2函数库实现验证码功能示例
2019/01/27 PHP
IE不出现Flash激活框的小发现的js实现方法
2007/09/07 Javascript
javascript document.referrer 用法
2009/04/30 Javascript
Firefox outerHTML实现代码
2009/06/04 Javascript
如何用javascript计算文本框还能输入多少个字符
2015/07/29 Javascript
Winform客户端向web地址传参接收参数的方法
2016/05/17 Javascript
jQuery on()方法绑定动态元素的点击事件实例代码浅析
2016/06/16 Javascript
jQuery绑定事件的四种方式介绍
2016/10/31 Javascript
JS控件bootstrap datepicker使用方法详解
2017/03/25 Javascript
MUI 解决动态列表页图片懒加载再次加载不成功的bug问题
2017/04/13 Javascript
ES6新特性之类(Class)和继承(Extends)相关概念与用法分析
2017/05/24 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
2017/07/17 Javascript
使用Ajax和Jquery配合数据库实现下拉框的二级联动的示例
2018/01/25 jQuery
Vue组件开发技巧总结
2018/03/04 Javascript
jQuery+CSS实现的标签页效果示例【测试可用】
2018/08/14 jQuery
Vue+ElementUI 中级联选择器Bug问题的解决
2020/07/31 Javascript
[43:32]Winstrike vs VGJ.S 2018国际邀请赛淘汰赛BO3 第一场 8.23
2018/08/24 DOTA
让python 3支持mysqldb的解决方法
2017/02/14 Python
python的构建工具setup.py的方法使用示例
2017/10/23 Python
利用Python将数值型特征进行离散化操作的方法
2018/11/06 Python
Python提取特定时间段内数据的方法实例
2019/04/01 Python
Python多线程threading模块用法实例分析
2019/05/22 Python
Pycharm添加虚拟解释器报错问题解决方案
2020/10/13 Python
Lou & Grey美国官网:主打舒适性面料服饰
2017/12/21 全球购物
手工制作的豪华英式沙发和沙发床:Willow & Hall
2019/05/03 全球购物
老师给学生的表扬信
2014/01/17 职场文书
《蚕姑娘》教学反思
2014/04/15 职场文书
院党委组织查摆问题对照检查材料思想汇报2014
2014/10/08 职场文书
2014年加油站站长工作总结
2014/12/23 职场文书
清明节网上祭英烈寄语2015
2015/03/04 职场文书
2015年保洁员工作总结
2015/05/04 职场文书
人与自然的观后感
2015/06/18 职场文书
2019年幼儿园管理条例范本!
2019/07/17 职场文书