一:列表解析
列表解析(List comprehensions)来自函数式编程语言Haskell 。它可以用来动态地创建列表。它在 Python 2.0 中被加入。
列表解析的语法: [expr for iter_var in iterable]
这个语句的核心是 for 循环,它迭代 iterable 对象的所有条目。前边的 expr 应用于序列的每个成员,最后的结果值是该表达式产生的列表。
比如一个计算序列成员的平方的 lambda 函数表达式:
>>> map(lambda x: x ** 2, range(6))
[0,1,4,9,16,25]
可以使用下面这样的列表解析来替换它:
>>> [x ** 2 for x in range(6)]
[0,1,4,9,16,25]
在新语句中,只有一次函数调用( range() ),而先前的语句中有三次函数调用(range() ,map() ,以及 lambda )。列表解析的表达式的效率更高。
结合if语句,列表解析还提供了一个扩展版本的语法:[expr for iter_var in iterable if cond_expr]
这个语法在迭代时会过滤/捕获满足条件表达式 cond_expr 的序列成员。
比如用于判断一个数值对象是奇数还是偶数的函数(奇数返回 1 ,偶数返回 0 ):
def odd(n):
return n % 2
可以使用filter() 和 lambda 挑选出序列中的奇数:
>>> seq = [11, 10, 9, 9, 10, 10, 9,8, 23, 9, 7, 18, 12, 11, 12]
>>> filter(lambda x: x % 2, seq)
[11,9,9,9,23,9,7,11]
也可以使用列表解析来完成操作,获得想要的数字:
>>> [x for x in seq if x % 2]
[11,9,9,9,23,9,7,11]
更多的例子:
迭代一个有三行五列的矩阵么:
>>> [(x+1, y+1) for x in range(3) for y in range(5)]
[(1,1),(1,2),(1,3),(1,4),(1,5),(2,1),(2,2),(2,
3),(2,4),(2,5),(3,1),(3,2),(3,3),(3,4),(3,5)]
计算纯英文文本文件中,所有非空白字符的数目:
可以像这样计算单词个数:
>>> f = open('hhga.txt’, 'r')
>>> len([word for line in f for word in line.split()])
91
可以把每个单词的长度加起来,得到和:
>>> f.seek(0)
>>> sum([len(word) for line in f for word in line.split()])
408
一个清晰明了的列表解析完成了之前需要许多行代码才能完成的工作! 如你所见,列表解析支持多重嵌套for 循环以及多个 if 子句。完整的语法可以在官方文档中找到。也可以在 PEP 202 中找到更多关于列表解析的资料。
二:生成器表达式
生成器表达式是列表解析的一个扩展。
生成器是在 Python 版本 2.2 时加入的一个重要特性。生成器是特定的函数,允许你返回一个值,然后"暂停"代码的执行,稍后恢复。
列表解析的一个不足就是必须生成所有的数据,用以创建整个列表。这在处理有大量数据的迭代器时有负面效应。生成器表达式通过结合列表解析和生成器解决了这个问题。
生成器表达式在 Python 2.4 被引入,它与列表解析非常相似,而且它们的基本语法基本相同。不过它并不真正创建数字列表,而是返回一个生成器。这个生成器在每次计算出一个条目后,把这个条目“产生”(yield)出来。生成器表达式使用了"延迟计算"(lazy evaluation),所以它在使用内存上更有效。
来看看它和列表解析到底有多相似:
列表解析:[expr for iter_var in iterable if cond_expr]
生成器表达式:(expr for iter_var in iterable if cond_expr)
在前边列表解析一节,计算文本文件中非空白字符总和。最后的代码中,我们展示了如何使用一行列表解析代码做所有的事。但是如果这个文件的大小变得很大,那么这行代码的内存性能会很低,因为我们要创建一个很长的列表用于存放单词的长度。
为了避免创建庞大的列表,可以使用生成器表达式来完成求和操作。它会计算每个单词的长度然后传递给 sum() 函数(它的参数不仅可以是列表,还可以是可迭代对象,比如生成器表达式)。这样,可以得到优化后的代码(代码长度,还有执行效率都很高效):
>>> sum(len(word) for line in data for word in line.split())
408
生成器表达式就好像是懒惰的列表解析(这反而成了它主要的优势)。它还可以用来处理其他列表或生成器,例如这里的 rows 和 cols:
rows = [1,2,3,17] def cols(): # example of simple generator
yield 56
yield 2
yield 1
不需要创建新的列表,直接就可以创建配对。可以使用下面的生成器表达式:
x_product_pairs = ((i, j) for i in rows for j in cols())
现在我们可以循环 x_product_pairs ,它会懒惰地循环 rows 和 cols:
>>> for pair in x_product_pairs:
...print pair
... (1,56)
(1,2)
(1,1)
(2,56)
(2,2)
(2,1)
(3,56)
(3,2)
(3,1)
(17,56)
(17,2)
(17,1)
在举一个冗长的样例,从它可以感觉到 Python 代码在这些年来的变化,看看如何改进代码。一个寻找文件最长的行的例子来,在以前,我们这样读取文件:
f = open('/etc/motd', 'r')
longest = 0 while True:
linelen = len(f.readline().strip())
if not linelen:
break
if linelen > longest:
longest = linelen
f.close()
return longest
事实上,这还不够老。真正的旧版本 Python 代码中,布尔常量应该写是整数 1 ,而且应该使用 string 模块而不是字符串的 strip() 方法:
import string
...
len(string.strip(f.readline()))
从那时起,我们认识到如果读取了所有的行,那么应该尽早释放文件资源。如果这是一个很多进程都要用到的日志文件,那么理所当然我们不能一直拿着它的句柄不释放。
所以读取文件的行的首选方法应该是这样:
f = open('/etc/motd', 'r')
longest = 0
allLines = f.readlines()
f.close() for line in allLines:
linelen = len(line.strip())
if linelen > longest:
longest = linelen return longest
列表解析允许我们稍微简化我们代码,而且我们可以在得到行的集合前做一定的处理。
f = open('/etc/motd', 'r')
longest = 0
allLines = [x.strip() for x in f.readlines()]
f.close() for line in allLines:
linelen = len(line)
if linelen > longest:
longest = linelen return longest
前两个例子在处理大文件时候都有问题,因为 readlines() 会读取文件的所有行。后来有了迭代器,文件本身就成为了它自己的迭代器,不需要调用 readlines() 函数。
我们已经做到了这一步,为什么不去直接获得行长度的集合呢(之前我们得到的是行的集合)? 这样,我们就可以使用 max() 内建函数得到最长的字符串长度:
f = open('/etc/motd', 'r')
allLineLens = [len(x.strip()) for x in f]
f.close()
return max(allLineLens)
这里唯一的问题就是你一行一行迭代 f 的时候,列表解析需要文件的所有行读取到内存中,然后生成列表。可以进一步简化代码:使用生成器表达式替换列表解析,然后把它移到 max()函数里,这样,所有的核心部分只有一行:
f = open('/etc/motd' , 'r')
longest = max(len(x.strip()) for x in f)
f.close()
return longest
最后,我们可以去掉文件打开模式(默认为读取),然后让 Python 去处理打开的文件。当然,文件用于写入的时候不能这么做:
return max(len(x.strip()) for x in open('/etc/motd'))
注意,即便是这只有一行的 Python 程序也不是很晦涩。可以在 PEP 289 中找到更多生成器表达式相关内容。
Python基础:08列表解析与生成器表达式的更多相关文章
-
Python中的列表解析和生成器表达式
Python中的列表解析和生成器表达式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.列表解析案例 #!/usr/bin/env python #_*_coding:utf-8 ...
-
Python基础(9)三元表达式、列表解析、生成器表达式
一.三元表达式 三元运算,是对简单的条件语句的缩写. # if条件语句 if x > f: print(x) else: print(y) # 条件成立左边,不成立右边 x if x > ...
-
Python全栈day18(三元运算,列表解析,生成器表达式)
一,什么是生成器 可以理解为一种数据类型,这种数据类型自动实现了迭代器协议(其他数据类型需要调用自己内置的__iter__方法),所以生成器是可迭代对象. 二,生成器分类在python中的表现形式 1 ...
-
python的迭代器、生成器、三元运算、列表解析、生成器表达式
一 迭代的概念 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前 ...
-
python 中的列表解析和生成表达式 - 转
优雅.清晰和务实都是python的核心价值观,如果想通过操作和处理一个序列(或其他的可迭代对象)来创建一个新的列表时可以使用列表解析( List comprehensions)和生成表达式,通过这两 ...
-
Day4 闭包、装饰器decorator、迭代器与生成器、面向过程编程、三元表达式、列表解析与生成器表达式、序列化与反序列化
一.装饰器 一.装饰器的知识储备 1.可变长参数 :*args和**kwargs def index(name,age): print(name,age) def wrapper(*args,**k ...
-
闭包、装饰器decorator、迭代器与生成器、面向过程编程、三元表达式、列表解析与生成器表达式
一.装饰器 一.装饰器的知识储备 不想修改函数的调用方式,但是还想在原来的函数前后添加功能 1.可变长参数 :*args和**kwargs def index(name,age): print(na ...
-
Python 迭代器之列表解析与生成器
 [TOC] 1. 列表解析 1.1 列表解析基础 列表解析把任意一个表达式应用到一个迭代对象中的元素 Python内置ord函数会返回一个字符的ASCII整数编码(chr函数是它的逆过程, 它将A ...
-
3、Python迭代器、列表解析及生成器(0530)
1.动态语言 sys.getrefcount() //查看对象的引用计数 增加对象的引用计数场景 对象创建时:以赋值的方式,创建变量名的同时就会创建变量 将对象添加进容器时:类似list.app ...
随机推荐
-
没听说过这些,就不要说你懂并发了,three。
引言 很久没有跟大家再聊聊并发了,今天LZ闲来无事,跟大家再聊聊并发.由于时间过去的有点久,因此LZ就不按照常理出牌了,只是把自己的理解记录在此,如果各位猿友觉得有所收获,就点个推荐或者留言激励下LZ ...
-
问题 “No mapping found for HTTP request with URI [/rbiz4/uploadFile.html]” 的解决
从以前的SpringMVC项目简化一下做个例子,结果出现了下面的错误: No mapping found for HTTP request with URI [/rbiz4/uploadFile.ht ...
-
打印datagridview内容 实现横向纵向分页(转)
网上找了很多打印的,只发现这个比较好,实现了横向纵向分页. 代码如下: using System;using System.Collections.Generic;using System.Text; ...
-
mac安装IE浏览器
1.首先得下载一个WineBottler for mac. 2.下载完毕之后,打开dmg文件后将WineBottler Combo里面的Wine和WineBottler这两个程序拖拉进应用程序. 3. ...
-
php 大流量网站访问
1:确认服务器硬件能否支持当前流量 2:数据库优化,用到什么字段查什么字段,减轻查询负担. 3:静态化,缓存,减少连库操作. 4:禁止外部盗链,减轻负载压力. 5:控制文件下载大小,尽量不超过2M,有 ...
-
【转】jQuery on()选择器函数
on()函数用于为指定元素的一个或多个事件绑定事件处理函数. 此外,你还可以额外传递给事件处理函数一些所需的数据. 从jQuery 1.7开始,on()函数提供了绑定事件处理程序所需的所有功能,用于统 ...
-
CSS学习笔记之元素分类
在讲解CSS布局之前,我们需要提前知道一些知识,在CSS中,html中的标签元素大体被分为三种不同的类型:块状元素.内联元素(又叫行内元素)和内联块状元素. 常用的块状元素有: <div> ...
-
Git学习之路(2)-安装GIt和创建版本库
▓▓▓▓▓▓ 大致介绍 前面一片博客介绍了Git到底是什么东西,如果有不明白的可以移步 Git学习之路(1)-Git简介 ,这篇博客主要讲解在Windows上安装Git和创建一个版本库 ▓▓▓▓▓▓ ...
-
在.NET Core类库中使用EF Core迁移数据库到SQL Server
前言 如果大家刚使用EntityFramework Core作为ORM框架的话,想必都会遇到数据库迁移的一些问题. 起初我是在ASP.NET Core的Web项目中进行的,但后来发现放在此处并不是很合 ...
-
转-HTTP POST GET SOAP本质区别详解
原文链接:HTTP POST GET SOAP本质区别详解 一 原理区别 一般在浏览器中输入网址访问资源都是通过GET方式:在FORM提交中,可以通过Method指定提交方式为GET或者POST,默认 ...