你翻看同事提交的代码,十个函数里有八个在用for循环遍历列表。数据量小的时候看不出问题,等列表里塞了几万条记录,程序跑起来像老牛拉破车。今天讲个办法,能让你少写一半循环代码。
用列表推导式代替简单循环,这是最基础的替换方案。比如要把列表中每个数字乘2,新手会写:
result = [] for num in numbers:
result.append(num 2)
高手直接写:
result = [num 2 for num in numbers]
这行代码干了同样的事,速度还快30%。不光数字操作,字符串处理也能套用。过滤奇数、提取字典某个键的值、条件拼接,全都塞进方括号里。
字典推导式和集合推导式同样好用。建一个字典把单词和长度对应起来,循环写法要五行,推导式一行搞定:
{word: len(word) for word in words}
去重还能顺便保留顺序,用字典的fromkeys方法。数据清洗时集合推导式能把重复项清得干干净净。
有人会说,逻辑复杂的时候推导式读起来费劲。这确实是个问题。我的建议是,嵌套循环和条件判断超过两层,就拆成普通循环。推导式不是银弹,它是给简单任务的快捷方式。
再往深走一步,map和filter函数能替代更多循环场景。map接收一个函数和一个可迭代对象,自动把函数作用到每个元素上。filter按条件筛选元素。配合lambda表达式用,代码能短得惊人。
list(map(str.upper, names)) list(filter(lambda x: x > 0, scores))
这两行代码分别做了大写转换和正数筛选。不用写循环,不用管索引,逻辑一目了然。
真正的杀手锏是itertools模块。这模块提供了几十个处理迭代器的函数。chain能一次性遍历多个列表,combinations能生成所有组合,groupby能把相邻的相同元素分组。处理排列组合问题时,循环写在纸面能写一页,用itertools三行完事。
from itertools import product for a, b in product(list1, list2):
print(a, b)
这段代码打印两个列表的所有组合,嵌套循环至少写四行。
数据量上了十亿级,生成器就派上用场了。生成器表达式不占内存,边取边算。同样的功能,列表推导式造出一个完整的list,生成器只在你需要下一个值的时候才计算。服务器内存吃紧的时候,这一招能救命。
total = sum(num 2 for num in range(100000000))
这里的sum配合生成器表达式,不产生中间列表,内存占用几乎为零。
你要是碰见需要按索引操作的情况,enumerate是个好帮手。它把索引和值一起打包给你,省得手动维护一个计数器变量。写循环时别再用range(len(...))那种老套写法了。
for i, value in enumerate(scores): if value < 60:
print(f'第{i}个不及格')
代码讲究的是清晰和效率。满屏的for循环不是罪,是没找到更好的工具。下次写循环前停两秒,想想有没有现成的函数能替代。Python的标准库和内置函数就是为消除样板代码设计的,你写循环是在跟语言设计者抢活干。
把这些技巧用熟了,同事看你代码会愣一下,然后默默回去删自己的for循环。代码短了,出错的地方自然就少了。下班时间提前几分钟,全靠这些细节堆出来。别再磨蹭了,打开编辑器试试吧。