
写代码的人都有过这种经历。一个列表,需要处理里面的每个元素。写个循环。循环里面判断条件。条件满足了做点操作。代码写完了,运行正常。过两天需求变了,要在处理前先过滤,处理后再排序。于是又加几行。再过几天,要处理的数据结构变了。搬砖开始。
问题出在写法上。大多数人写代码是“命令式”的。告诉机器先干这个,再干那个。机器听话。人累。
有个写法叫“声明式”。我只说我要什么结果。过程机器自己去想。Python里有个东西叫推导式。列表推导式、字典推导式、集合推导式。名字听起来像语法糖。用好了是效率工具。
看个例子。有一个列表,里面是数字。要挑出偶数,每个乘以2,结果放新列表。
普通写法
result = [] for num in numbers: if num % 2 == 0: result.append(num * 2)
四行。推导式写法:
推导式写法
result = [num * 2 for num in numbers if num % 2 == 0] 一行。
读起来像一句话。取出每个数字,如果是偶数,乘以2,组成列表。顺序跟人的思维一致。 代码短了。可读性高了。维护成本低了。这还只是开始。
推导式真正的价值不在省行数
在它改变了你思考数据的方式。你不再想“怎么一步步做”。你想“我要什么”。这个转变能省掉大量中间变量。中间变量少了,bug就少。bug少了,加班就少。
很多人用推导式只用在简单场景。稍微复杂一点就退回循环。这是浪费。推导式可以嵌套。可以有多个for。可以有多个if。可以处理字典和集合。
比如,要把一个矩阵转置。矩阵是列表的列表。
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] transposed = [[row[i] for row in matrix] for i in range(len(matrix[0]))]
一行。两层推导式。外层控制列索引。内层取每行的对应元素。读起来有点绕。写习惯了就顺。
再比如,合并两个列表,过滤掉重复项,保持顺序。
merged = list(dict.fromkeys(a + b))
没用推导式。用了字典的有序特性。这行代码比手写循环去重快得多。也安全得多。手写循环去重容易漏掉边界情况。用内置结构处理内置问题,这是Python的设计哲学。
关于性能的误解
有人担心推导式性能。说它比循环慢。这是误解。推导式在CPython里的实现就是优化过的循环。它避免了反复调用append方法。它预分配内存。大多数场景下,推导式比手写循环快。数据量越大,差距越明显。
但推导式不是万能的。有些情况不该用。
逻辑超过两个条件分支。用推导式会变得难读。嵌套超过两层。用推导式会让人头晕。有副作用操作。比如打印日志、写文件。推导式里做这些事是坏味道。该用循环就用循环。
工具是好工具。用对地方才是好工具。
思维方式才是核心
真正让效率提升的,是推导式背后的思维方式。你开始把操作分成两类:转换和过滤。转换用表达式。过滤用条件。组合起来就是一条数据流水线。这条流水线可以复用。可以测试。可以替换其中任何一段。
这种思维扩展到函数式编程。map、filter、reduce。Python里这些函数跟推导式是亲戚。推导式更直观。map和filter更抽象。抽象有抽象的好处。可以把函数当参数传。可以组合。可以延迟计算。
看个实际场景。读一个日志文件。每行格式是“时间 级别 消息”。要统计每个级别的出现次数。普通写法要打开文件、循环、分割、判断、累加。用推导式加Counter:
from collections import Counter with open('log.txt') as f: levels = [line.split()[1] for line in f if line.strip()] counts = Counter(levels)
三行。逻辑清晰。读文件、提取级别、计数。每一步都是独立的。可以单独测试。可以单独替换。改需求的时候只动需要动的那一步。
这种写法还有个隐藏好处。它让代码更容易并行化。推导式里的操作如果无状态,可以扔给多进程或多线程。手写循环里有各种中间变量和状态,并行化要改很多。
再说一个场景。处理嵌套字典。要取出所有特定键的值。普通写法写递归函数。推导式写法:
def extract_values(obj, key): if isinstance(obj, dict): for k, v in obj.items(): if k == key: yield v yield from extract_values(v, key) elif isinstance(obj, list): for item in obj: yield from extract_values(item, key) values = list(extract_values(data, 'target'))
用了生成器。生成器跟推导式是一家人。推导式是生成器的语法糖。生成器是惰性的。数据流进来一个处理一个。内存占用恒定。处理大文件、大列表的时候,这是救命的。
很多人写代码习惯先把所有数据加载到内存。然后处理。数据小的时候没问题。数据大的时候程序崩溃。用生成器改写,内存问题消失。代码结构不变。只是把方括号换成圆括号。或者把return换成yield。
这些技巧都不难。难的是改变习惯。习惯改了,效率自然上来。
短代码不等于难读
有人会说,代码短了不好读。这是错觉。短代码不等于难读。长代码也不等于好读。可读性取决于逻辑是否清晰。推导式把“做什么”和“怎么做”分开了。读代码的人先看到“做什么”。需要的时候再看“怎么做”。这是更好的信息层次。
写代码的时间只占一小部分。读代码的时间占大部分。让自己和别人读得轻松,就是省时间。省下来的时间不用来加班。
从明天开始,遇到循环先想一下。能不能写成推导式。能不能用生成器。能不能用内置函数。想三秒钟。这三秒钟能省三十分钟。
以上就是“学会这个Python技巧,效率提升10倍,代码从此不加班!”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14512/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料