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删除指定目录下过期文件的2个脚本分享
Apr 10 Python
Python遍历目录中的所有文件的方法
Jul 08 Python
用Python将IP地址在整型和字符串之间轻松转换
Mar 22 Python
numpy使用fromstring创建矩阵的实例
Jun 15 Python
在Pycharm中将pyinstaller加入External Tools的方法
Jan 16 Python
Python爬虫之UserAgent的使用实例
Feb 21 Python
python ChainMap的使用和说明详解
Jun 11 Python
python实现将文件夹内的每张图片批量分割成多张
Jul 22 Python
django实现支付宝支付实例讲解
Oct 17 Python
如何使用Python破解ZIP或RAR压缩文件密码
Jan 09 Python
Python class的继承方法代码实例
Feb 14 Python
Python帮你解决手机qq微信内存占用太多问题
Feb 15 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
CodeIgniter框架中_remap()使用方法2例
2014/03/10 PHP
php获取一个变量的名字的方法
2014/09/05 PHP
PHP中字符安全过滤函数使用小结
2015/02/25 PHP
PHP类相关知识点实例总结
2016/09/28 PHP
YII2框架中使用yii.js实现的post请求
2017/04/09 PHP
ThinkPHP+EasyUI之ComboTree中的会计科目树形菜单实现方法
2017/06/09 PHP
PHP魔术方法之__call与__callStatic使用方法
2017/07/23 PHP
Laravel框架中自定义模板指令总结
2017/12/17 PHP
Yii2.0框架模型多表关联查询示例
2019/07/18 PHP
javascript打印大全(打印页面设置/打印预览代码)
2013/03/29 Javascript
jQuery根据ID获取input、checkbox、radio、select的示例
2014/08/11 Javascript
jquery实现TAB选项卡鼠标经过带延迟效果的方法
2015/07/27 Javascript
简介BootStrap model弹出框的使用
2016/04/27 Javascript
js实现淡入淡出轮播切换功能
2017/01/13 Javascript
vuejs2.0运用原生js实现简单的拖拽元素功能示例
2017/02/24 Javascript
详解JS获取HTML DOM元素的8种方法
2017/06/17 Javascript
JavaScript 程序错误Cannot use 'in' operator to search的解决方法
2017/07/10 Javascript
详谈js对url进行编码和解码(三种方式的区别)
2017/08/16 Javascript
Vue.js实现按钮的动态绑定效果及实现代码
2017/08/21 Javascript
Node.js 使用流实现读写同步边读边写功能
2017/09/11 Javascript
浅谈JavaScript的innerWidth与innerHeight
2017/10/12 Javascript
jquery获取元素到屏幕四周可视距离的方法
2018/09/05 jQuery
解决vue项目nginx部署到非根目录下刷新空白的问题
2018/09/27 Javascript
vue 子组件修改data或调用操作
2020/08/07 Javascript
js数组的基本使用总结
2021/01/18 Javascript
python备份文件以及mysql数据库的脚本代码
2013/06/10 Python
Python中用startswith()函数判断字符串开头的教程
2015/04/07 Python
Python实现的redis分布式锁功能示例
2018/05/29 Python
Django contenttypes 框架详解(小结)
2018/08/13 Python
python实现简单学生信息管理系统
2020/04/09 Python
python 操作excel表格的方法
2020/12/05 Python
ET Mall东森购物网:东森严选
2017/03/06 全球购物
农民工工资发放承诺书
2014/03/31 职场文书
恰同学少年观后感
2015/06/08 职场文书
深入理解以DEBUG方式线程的底层运行原理
2021/06/21 Java/Android
使用Nginx+Tomcat实现负载均衡的全过程
2022/05/30 Servers