Fluent Python 学习--列表解析生成器表达式


列表解析(推导)和生成器表达式

1 列表推导

列表推导式构建列表的快捷方式,生成器表达式则可以用来
创建其他任何类型的序列

1.1 列表解析的代码易读性

先看for循环的方式

symblos = "abcdef"
codes = []
for symblo in symblos:
	codes.append(ord(symblo))
print(codes)

列表解析

symblos = "abcdef"
codes = [ord(symblo) for symblo in symblos]
print(codes)

列表推导也可能被滥.用通常的原则是,只用列表推导来创建新的列表,并且尽量保持简短。如果列表推导的代码超过了两行,你可能就要考虑是不是得用 for 循环重写了

1.2 解决变量泄露的问题

Python中的列表中for后面和前面有同名变量,在Python2中会覆盖,在Python3中没有问题。

#Python2中
>>> x='hello'   #这个全局变量x
>>> code = [x for x in 'abc']
>>> x
'c'   # 经过for循环后x会用c替换hello

Python3中

x = 'hello'
code = [x for x in "abc"]
print(x)  # 结果是hello

在Python3中的列表解析,有自己的局部作用域,类似函数。(生成器表达式也是同样的)
表达式内部的变量和赋值只在内部起作用。表达式的上下文里的同名变量还可以被正常引用,局部变量并不会影响到它们。

1.3 列表推导同filter和map的比较

filter 和 map 合起来能做的事情,列表推导也可以做,而且还不需要借助难以理解和阅读的 lambda 表达式

symblos = "abcdef"
code =list(filter(lambda c:c>99,map(ord,symblos)))
print(code)

filter(函数,sequence)
map(函数,sequence)

fliter/map 组合不一定比列表解析快

下面的代码是书中的测试代码,
代码地址:

https://github.com/fluentpython/example-code/blob/master/02-array-seq/listcomp_speed.py#L8

import timeit

TIMES = 10000

SETUP = """
symbols = '$¢£¥€¤'
def non_ascii(c):
    return c > 127
"""

def clock(label, cmd):
    res = timeit.repeat(cmd, setup=SETUP, number=TIMES)
    print(label, *('{:.3f}'.format(x) for x in res))

clock('listcomp        :', '[ord(s) for s in symbols if ord(s) > 127]')
clock('listcomp + func :', '[ord(s) for s in symbols if non_ascii(ord(s))]')
clock('filter + lambda :', 'list(filter(lambda c: c > 127, map(ord, symbols)))')
clock('filter + func   :', 'list(filter(non_ascii, map(ord, symbols)))')
listcomp        : 0.017 0.013 0.014
listcomp + func : 0.019 0.020 0.019
filter + lambda : 0.017 0.019 0.025
filter + func   : 0.021 0.023 0.024
listcomp        : 0.013 0.014 0.013
listcomp + func : 0.020 0.020 0.023
filter + lambda : 0.024 0.022 0.022
filter + func   : 0.016 0.016 0.016

结果是list快于filter/map,运行的时候确保自己的机器没有运行占用CPU的软件

1.4 笛卡尔积

用列表解析可以生成两个或者以上的可迭代笛卡尔积,笛卡尔积是一个列表,列表里的元素是由输入的可迭代类型的元素对构成的元组,因此笛卡儿积列表的长度等于输入变量的长度的乘积

1.4.1 Python 实现

  • 列表解析的方式
colors = ['blck','white']
sizes = ['S','M','L']
tshits = [(color,size) for color in colors for size in sizes]
print(tshits)

python中的[] {} () 会忽略其中的换行,就不用\来表示

  • for 循环的方法
colors = ['blck','white']
sizes = ['S','M','L']
for color in colors:
	for size in sizes:
		print(color,size)

2 生成器表达式

生成器表达式可以推导出元组、数组或者其他数据类型,生成器的原理是迭代器协议。把[]换成()就是生成器

生成器取的时候通过next取,只能一个个的取,通过for循环能全部取出来

symblos = "abcdef"
code = (ord(symbol) for symbol in symblos)
print(next(code))#一个个的取

#通过for循环遍历
for i in code:
	print(i)

通过生成器生成元组

symblos = "abcdef"
code = tuple(ord(symbol) for symbol in symblos)
print(type(code))# tuple

通过生成器生成数组

import array

symblos = "abcdef"
code=array.array('I',(ord(symbol) for symbol in symblos))
print(code)

# 这个是数组的第一个参数(must be b, B, u, h, H, i, I, l, L, q, Q, f or d)

使用生成器生成笛卡尔积

通过for循环遍历全部生成

colors = ['blck','white']
sizes = ['S','M','L']
for i in ((color,size) for color in colors for size in sizes):
	print(i)
posted @ 2017-06-07 17:32  hzxPeter  阅读(262)  评论(0)    收藏  举报