【Python】推导式与生成器
python 推导式
推导式comprehensions(又称解析式)
(一)、列表推导式(list comprehension)
语法规范:
out_list = [ out_express for out_express in input_list if out_express_condition]
其中的 if 条件判断根据需要可有可无。
# 0 ~ 9 中的偶数
a = [i for i in range(10) if i % 2 == 0]
print(a)
# [0, 2, 4, 6, 8]
不使用列表推导式的一般用法:
a = []
for i in range(10):
if i % 2 == 0:
evens.append(i)
带嵌套循环的推导式
把一个矩阵(以列表为元素的列表)展平为一个列表。
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
a = [i for row in matrix for i in row]
print(a)
# [1, 2, 3, 4, 5, 6, 7, 8, 9]
不使用列表推导式的一般用法:
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
a = []
for row in matrix:
for i in row:
a.append(i)
print(a)
带嵌套循环的推导式的断行:
# a = [i for row in matrix for i in row]
a = [
i
for row in matrix
for i in row
]
(二)、字典推导式(dict comprehensions)
我们看先来看使用字典推导式的基础模板:{ key:value for key,value in existing_data_structure }
这里和list有所不同,因位dict里面有两个关键的属性,key 和 value,但大同小异,我们现在的expression部分可以同时对 key 和 value 进行操作
mcase = {'a': 10, 'A': 7,'b': 34, 'Z': 3}
mcase_frequency = {k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0) for k in mcase.keys()}
# {'a': 17, 'b': 34, 'z': 3}
进行断行:
mcase = {'a': 10, 'A': 7,'b': 34, 'Z': 3}
mcase_frequency = {
k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
for k in mcase.keys()
}
# {'a': 17, 'b': 34, 'z': 3}
不使用字典推导式的一般用法:
mcase = {'a': 10, 'A': 7,'b': 34, 'Z': 3}
mcase_frequency = {}
for key in mcase.keys():
mcase_frequency.setdefault(key, mcase.get(key.lower(), 0) + mcase.get(key.upper(), 0) )
print(mcase_frequency)
# {'a': 17, 'b': 34, 'z': 3}
#字典推导式还可以快速对换一个字典的键和值
#{v: k for k, v in some_dict.items()}
mcase = {'a': 10, 'A': 7,'b': 34, 'Z': 3}
mcase_frequency = {v:k for k, v in mcase.items()}
print(mcase_frequency)
# {10: 'a', 7: 'A', 34: 'b', 3: 'Z'}
(三)、集合推导式(set comprehensions)
它们跟列表推导式也是类似的。 唯一的区别在于它们使用大括号{}
注:
(1)可以使用大括号 { } 或者 set() 函数创建集合,
(2)创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。
(3)集合推导式去除重复值
my_set = {i * i for i in [-1, 1, 2, -2, 3]}
print(my_set)
# {1, 4, 9}
需要保持集合的特点:不能含有重复元素。
生成器(Generators)
以上介绍了 列表、字典、集合三个推导式。同样元组也有同样变化,但是称为生成器表达式
当序列过长, 而每次只需要获取一个元素时,应当考虑使用生成器表达式而不是列表解析。生成器表达式的语法和列表解析一样,只不过生成器表达式是被()括起来的,而不是[],如下:
(expr for iter_var in iterable)
(expr for iter_var in iterable if cond_expr)
my_generator = (i for i in range(5)) # 返回一个生成器
print(my_generator)
#<generator object <genexpr> at 0x000002562ECC2120>
my_generator = (i for i in range(5)) # 返回一个生成器
for i in my_generator:
print(i)
# 0 1 2 3 4
生成器表达式并不真正创建数字列表, 而是返回一个生成器,这个生成器在每次计算出一个条目后(调用的时候再计算),使用了“惰性计算”(lazy evaluation)
生成器与推导式的优缺点
1.列表推导式是将所有的值一次性加载到内存中
优点:
(1)如果生成列表的方式不太复杂,这是建议使用列表推导式,其内部是通过cpython来实现的较用for循环要快
(2)列表推导式可以遍历任意次
2.生成器是将列表推导式的[]改成() 或者 使用yield关键字编写
优点:不会将所有的值一次性加载到内存中,延迟计算,一次返回一个结果,它不会一次生成所有的结果,这对大数据量处理,非常有用
缺点:生成器只能遍历一次,即不能向前读取数据
# 如果生成列表的方式不太复杂,这是建议使用列表推导式,其内部是通过cpython来实现的比较用for循环要快
from time import perf_counter
from functools import wraps
def spend_time(func):
@wraps(func)
def decorate_func(*args,**kwargs):
start = perf_counter()
func()
all = perf_counter()-start
print(all)
return decorate_func
@spend_time
def for_func():
mylist=[]
all = range(1000000)
for i in all:
mylist.append(i)
@spend_time
def list_finc():
mylsit=[i for i in range(1000000)]
if __name__ == '__main__':
for_func()
list_finc()
结果为:
0.10319479999998293
0.06540830000085407