Python中的列表生成式与生成器学习教程


Posted in Python onMarch 13, 2016

列表生成式
即创建列表的方式,最笨的方法就是写循环逐个生成,前面也介绍过可以使用range()函数来生成,不过只能生成线性列表,下面看看更为高级的生成方式:

>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

写列表生成式时,把要生成的元素x * x放到前面,后面跟for循环,就可以把list创建出来,十分有用,多写几次,很快就可以熟悉这种语法。
你甚至可以在后面加上if判断:

>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

循环嵌套,全排列:

>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

看一个简单应用,列出当前目录下所有文件和目录:

>>> import os
>>> [d for d in os.listdir('.')]
['README.md', '.git', 'image', 'os', 'lib', 'sublime-imfix', 'src']

前面也说过Python里循环中可以同时引用两个变量,所以生成变量也可以:

>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.iteritems()]
['y=B', 'x=A', 'z=C']

也可以通过一个list生成另一个list,例如把一个list中所有字符串变为小写:

>>> L = ['Hello', 'World', 'IBM', 'Apple']
>>> [s.lower() for s in L]
['hello', 'world', 'ibm', 'apple']

但是这里有个问题,list中如果有其他非字符串类型,那么lower()会报错,解决办法:

>>> L = ['Hello', 'World', 'IBM', 'Apple', 12, 34]
>>> [s.lower() if isinstance(s,str) else s for s in L]
['hello', 'world', 'ibm', 'apple', 12, 34]

此外,列表生成式还有许多神奇用法,说明请看注释:

#!/usr/bin/env python3 
# -*- coding: utf-8 -*- 
 
list(range(1, 11)) 
 
# 生成1乘1,2乘2...10乘10 
L = [] 
for x in range(1, 11): 
  L.append(x * x) 
 
# 上面太麻烦,看下面 
[x * x for x in range(1, 11)] 
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 
 
# 加上if,就可以筛选出仅偶数的平方 
[x * x for x in range(1, 11) if x % 2 == 0] 
# [4, 16, 36, 64, 100] 
 
# 两层循环,可以生成全排列 
[m + n for m in 'ABC' for n in 'XYZ'] 
# ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] 
 
# 列出当前目录下的所有文件和目录名 
import os 
[d for d in os.listdir('.')] # on.listdir可以列出文件和目录 
 
# 列表生成式也可以使用两个变量来生成list: 
d = {'x': 'A', 'y': 'B', 'z': 'C'} 
[k + '=' + v for k, v in d.items()] 
# ['x=A', 'z=C', 'y=B'] 
 
# 把一个list中所有的字符串变成小写 
L = ['Hello', 'World', 'IBM', 'Apple'] 
[s.lower() for s in L] 
# ['hello', 'world', 'ibm', 'apple'] 
 
L1 = ['Hello', 'World', 18, 'Apple', None] 
L2 = [s.lower() for s in L1 if isinstance(s, str)] 
print(L2) 
# ['hello', 'world', 'apple'] 
# isinstance函数可以判断一个变量是不是字符串

生成器
列表生成式虽然强大,但是也会有一个问题,当我们想生成一个很大的列表时,会非常耗时,并且占用很大的存储空间,关键是这里面的元素可能你只需要用到前面很少的一部分,大部分的空间和时间都浪费了。Python提供了一种边计算边使用的机制,称为生成器(Generator),创建一个Generator最简单的方法就是把[]改为():

>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x7fe73eb85cd0>

如果要一个一个打印出来,可以通过generator的next()方法:

>>> g.next()
0
>>> g.next()
1
>>> g.next()
4
>>> g.next()
9
>>> g.next()
16
>>> g.next()
25
>>> g.next()
36
>>> g.next()
49
>>> g.next()
64
>>> g.next()
81
>>> g.next()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

其实generator object也是可迭代的,所以可以用循环打印,还不会报错。

>>> g = (x * x for x in range(10))
>>> for n in g:
...   print n
...

这是简单的推算算法,但是如果算法比较复杂,写在()里就不太合适了,我们可以换一种方式,使用函数来实现。
比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, …
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:

def fib(max):
  n, a, b = 0, 0, 1
  while n < max:
    print b
    a, b = b, a + b
    n = n + 1

上面的函数可以输出斐波那契数列的前N个数,这个也是通过前面的数推算出后面的,所以可以把函数变成generator object,只需要把print b改为yield b即可。

def fib(max):
  n, a, b = 0, 0, 1
  while n < max:
    yield b
    a, b = b, a + b
    n = n + 1

如果一个函数定义中包含了yield关键字,这个函数就不在是普通函数,而是一个generator object。

>>> fib(6)
<generator object fib at 0x7fa1c3fcdaf0>
>>> fib(6).next()
1

所以要想调用这个函数,需要使用next()函数,并且遇到yield语句返回(可以把yield理解为return):

def odd():
  print 'step 1'
  yield 1
  print 'step 2'
  yield 3
  print 'step 3'
  yield 5

看看调用输出结果:

>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

同样也可以改为for循环语句输出。例如:

def odd():
  print 'step 1'
  yield 1
  print 'step 2'
  yield 2
  print 'step 3'
  yield 3

if __name__ == '__main__':
  o = odd()
  while True:
    try:
      print o.next()
    except:
      break
Python 相关文章推荐
python不带重复的全排列代码
Aug 13 Python
一张图带我们入门Python基础教程
Feb 05 Python
python抓取需要扫微信登陆页面
Apr 29 Python
python Django编写接口并用Jmeter测试的方法
Jul 31 Python
ubuntu上安装python的实例方法
Sep 30 Python
python使用pygame实现笑脸乒乓球弹珠球游戏
Nov 25 Python
flask的orm框架SQLAlchemy查询实现解析
Dec 12 Python
python每5分钟从kafka中提取数据的例子
Dec 23 Python
Python测试Kafka集群(pykafka)实例
Dec 23 Python
Python使用pickle进行序列化和反序列化的示例代码
Sep 22 Python
关于python scrapy中添加cookie踩坑记录
Nov 17 Python
从Pytorch模型pth文件中读取参数成numpy矩阵的操作
Mar 04 Python
jupyter安装小结
Mar 13 #Python
Ubuntu下安装PyV8
Mar 13 #Python
Python连接MySQL并使用fetchall()方法过滤特殊字符
Mar 13 #Python
深入讲解Python函数中参数的使用及默认参数的陷阱
Mar 13 #Python
编写Python小程序来统计测试脚本的关键字
Mar 12 #Python
使用Python内置的模块与函数进行不同进制的数的转换
Mar 12 #Python
Python语言的面相对象编程方式初步学习
Mar 12 #Python
You might like
手冲咖啡应该是现代精品咖啡店的必备选项吗?
2021/03/03 冲泡冲煮
PHP获取当前文件所在目录 getcwd()函数
2009/05/13 PHP
php array的学习笔记
2012/05/10 PHP
php检测网页是否被百度收录的函数代码
2013/10/09 PHP
php中的路径问题与set_include_path使用介绍
2014/02/11 PHP
Drupal7 form表单二次开发要点与实例
2014/03/02 PHP
PHP中的魔术方法总结和使用实例
2015/05/11 PHP
完美解决phpdoc导出文档中@package的warning及Error的错误
2016/05/17 PHP
php实现微信公众号创建自定义菜单功能的实例代码
2019/06/11 PHP
PHP如何使用cURL实现Get和Post请求
2020/07/11 PHP
jquery 页面全选框实践代码
2010/04/02 Javascript
js constructor的实际作用分析
2011/11/15 Javascript
基于jquery的固定表头和列头的代码
2012/05/03 Javascript
利用JQuery动画制作滑动菜单项效果实现步骤及代码
2013/02/07 Javascript
jquery 绑定回车动作扑捉回车键触发的事件
2014/03/26 Javascript
js实现无限级树形导航列表效果代码
2015/09/23 Javascript
详解JavaScript for循环中发送AJAX请求问题
2020/06/23 Javascript
jquery实现多次上传同一张图片
2017/01/09 Javascript
ionic2打包android时gradle无法下载的解决方法
2017/04/05 Javascript
vue如何获取点击事件源的方法
2017/08/10 Javascript
mint-ui在vue中的使用示例
2018/04/05 Javascript
Vuejs通过拖动改变元素宽度实现自适应
2020/09/02 Javascript
[48:39]Ti4主赛事胜者组第一天 EG vs NEWBEE 2
2014/07/19 DOTA
详解python中requirements.txt的一切
2017/03/03 Python
Python 中 list 的各项操作技巧
2017/04/13 Python
利用Python自带PIL库扩展图片大小给图片加文字描述的方法示例
2017/08/08 Python
python中利用h5py模块读取h5文件中的主键方法
2018/06/05 Python
对dataframe进行列相加,行相加的实例
2018/06/08 Python
PyQt5 界面显示无响应的实现
2020/03/26 Python
全球领先的鞋类零售商:The Walking Company
2016/07/21 全球购物
lookfantastic荷兰:在线购买奢华护肤、护发和化妆品
2018/11/27 全球购物
入党积极分子介绍信
2014/01/17 职场文书
计算机专业毕业生自荐信范文
2014/03/06 职场文书
宣传标语大全
2014/07/01 职场文书
警察群众路线整改措施
2014/09/26 职场文书
解决Mysql中的innoDB幻读问题
2022/04/29 MySQL