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多进程共享变量
Apr 06 Python
Python的消息队列包SnakeMQ使用初探
Jun 29 Python
深入理解Python中的内置常量
May 20 Python
Python使用numpy实现BP神经网络
Mar 10 Python
关于python2 csv写入空白行的问题
Jun 22 Python
浅谈python实现Google翻译PDF,解决换行的问题
Nov 28 Python
python 执行文件时额外参数获取的实例
Dec 18 Python
深入学习python多线程与GIL
Aug 26 Python
Python如何实现FTP功能
May 28 Python
学python需要去培训机构吗
Jul 01 Python
Python实现简单的猜单词小游戏
Oct 28 Python
Python 实现定积分与二重定积分的操作
May 26 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
mysql总结之explain
2012/02/27 PHP
探讨:如何使用PHP实现计算两个日期间隔的年、月、周、日数
2013/06/13 PHP
javascrpt绑定事件之匿名函数无法解除绑定问题
2012/12/06 Javascript
javascript实现页面内关键词高亮显示代码
2014/04/03 Javascript
js判断是否按下了Shift键的方法
2015/01/27 Javascript
JQuery实现防止退格键返回的方法
2015/02/12 Javascript
在Node.js应用中读写Redis数据库的简单方法
2015/06/30 Javascript
JS学习笔记之贪吃蛇小游戏demo实例详解
2019/05/29 Javascript
原生JavaScript之es6中Class的用法分析
2020/02/23 Javascript
JavaScript canvas基于数组生成柱状图代码实例
2020/03/06 Javascript
vue+node 实现视频在线播放的实例代码
2020/10/19 Javascript
[01:50]WODOTA制作 DOTA2中文宣传片《HERO》
2013/04/28 DOTA
[11:27]《一刀刀一天》之DOTA全时刻20:TI4总奖金突破920W TS赛事分析
2014/06/18 DOTA
python使用opencv读取图片的实例
2017/08/17 Python
PyQt5 QListWidget选择多项并返回的实例
2019/06/17 Python
python中pytest收集用例规则与运行指定用例详解
2019/06/27 Python
Python实现的远程文件自动打包并下载功能示例
2019/07/12 Python
python用match()函数爬数据方法详解
2019/07/23 Python
python如何通过twisted搭建socket服务
2020/02/03 Python
基于Python爬取股票数据过程详解
2020/10/21 Python
如何用Python编写一个电子考勤系统
2021/02/08 Python
基于HTML5陀螺仪实现ofo首页眼睛移动效果的示例
2017/07/31 HTML / CSS
美国学校校服,儿童和婴儿服装:Cookie’s Kids
2016/10/14 全球购物
英国家用电器购物网站:Hughes
2018/02/23 全球购物
GoDaddy英国:全球排名第一的域名注册商
2018/06/08 全球购物
Dodax奥地利:音乐、电影、书籍、玩具、电子产品等
2019/08/31 全球购物
意大利时尚奢侈品店:D’Aniello Boutique
2021/01/19 全球购物
意大利和国际奢侈品牌购物网站:Suitnegozi.com
2021/01/15 全球购物
金融专业推荐信
2013/11/14 职场文书
酒店出纳岗位职责
2013/12/29 职场文书
旅游个人求职信范文
2014/01/30 职场文书
政府个人对照检查材料思想汇报
2014/10/08 职场文书
2015年安全生产管理工作总结
2015/05/25 职场文书
担保书格式范文
2015/09/22 职场文书
机关干部作风整顿心得体会
2016/01/22 职场文书
导游词之青岛崂山
2019/12/27 职场文书