列表解析表达式
先来看一个例子~ Leetcode 171 题
解法很简单:
sum = 0
for i in range(0, len(s):
sum += 26 ** (len(s) - 1 - i) * (ord(s[i]) - ord("A") + 1)
return sum
那么,这里也可以这么写。
return sum([26 ** (len(s) - 1 - i) * (ord(s[i]) - ord("A") + 1) for i in range(0, len(s))])
下面的简写方法,我们称作 python的列表解析表达式
。酷酷的 o(╥﹏╥)o有没有
再来延伸看一下这么写的好处(内存占用)
上代码:
import timeit
import os
import psutil
# 准备一个5000w 元素的列表 备用
list = range(0, 50000000)
# 计算占用内存
def show_memory_info(hint):
pid = os.getpid()
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024. / 1024
print('{} memory used: {} MB'.format(hint, memory))
# 时间
start1 = timeit.default_timer()
# 1.普通方法遍历元素,append 到新列表
list1 = []
for x in (list):
if x == 20000000:
show_memory_info('1')
if x > 4:
list1.append(x)
show_memory_info('2')
end1 = timeit.default_timer()
print('Running time: {} Seconds'.format(end1 - start1))
start2 = timeit.default_timer()
show_memory_info('3')
# 2. 生成器生成元素到新列表,注意这里没有赋值到新列表
(x for x in (list) if x > 4)
show_memory_info('4')
end2 = timeit.default_timer()
print('Running time: {} Seconds'.format(end2 - start2))
运行程序,得到的结果如下:
1 memory used: 783.5625 MB
2 memory used: 1945.28125 MB
Running time: 11.129049652 Seconds
3 memory used: 1945.28125 MB
4 memory used: 1945.28125 MB
Running time: 0.09404864300000071 Seconds
关注几点:
-
时间上的差别1:
普通遍历
时间为9秒,而生成器遍历
(没有创建新列表时间为0.09秒),这个原因在我之前的迭代和生产的对比 博客也写过了,是因为只调用了算法 -
时间上的差别2: 如果我把
list1.apped
给删除了,也就是普通遍历的append 操作删除了,时间是 6s 左右 ,看来普通遍历确实要比生成器占用更多的内存(废话),时间也更长 -
时间上的关注点3:如果我把生成器赋值
list2 = (x for x in (list) if x > 4) ,这段代码的时间是4秒。
可得出,生成器本身生生成元素只是调用了算法,而并未赋值(实际占用内存) -
内存上的关注点: 同3所说,生成器赋值才产生内存占用,故而更快。
思考
语法糖其实是迭代的一个延伸,合理的运用不仅可以使代码变酷,让别人看不懂,也是可以优化程序运行速度和内存占用的。