Python 列表推导式示例

列表推导式说三件事:产出什么,哪个循环提供元素,以及可选的哪些元素能留下来。短写法很有用,但它的可读性有一条硬上限。下面的例子既讲语法,也讲该在哪儿停手。

🎙️ 发布并录制于: ·

核心的四种写法

从中间的 for n in nums 开始读,再把左边的表达式当成输出。做筛选的 if 放在最右边,它可以把元素丢掉。if-else 要放在 for 前面,因为它是在挑输出的值,元素一个都不会少。

nums = [1, 2, 3, 4, 5]

[n * n for n in nums]                # transform → [1,4,9,16,25]
[n for n in nums if n % 2 == 0]     # filter → [2,4]
[n*n for n in nums if n > 2]        # both → [9,16,25]
["even" if n%2==0 else "odd" for n in nums]  # choose

位置决定含义。右边的 if 是留下还是丢掉。左边的 if-else 是取这个值还是取那个值。

真实场景里的一行代码

好的推导式只做一次能一眼认出来的转换,最多再加一个简单的筛选。清洗字符串顺手丢掉空串、从活跃用户里取 email 字段,都过得了这个标准。按后缀筛文件名也读得顺,因为条件就挨着它控制的那个循环。

# clean strings and discard blanks
[s.strip().lower() for s in raw if s.strip()]

# pull a field from active API users
[u["email"] for u in users if u["active"]]

# parse numeric fields
[float(x) for x in fields]

# filenames matching a suffix
[f for f in os.listdir(".") if f.endswith(".csv")]

真要处理 CSV 数据,别用一行字符串按逗号切分去造 fields;带引号的逗号会让这个捷径失效。先把这一行交给 Python 的 CSV 模块,再用推导式转换已经解析好的字段。

字典、集合,和一层展平

花括号里写键和值,得到字典。花括号里只写一个表达式,得到集合,重复值自动去掉。要展平一层嵌套,就按等价嵌套循环的顺序,从左到右写这些 for:先是每一行,再是这一行里的每个元素。

{w: len(w) for w in words}            # dict: word → length
{u["id"]: u for u in users}          # index records by id
{n % 3 for n in nums}                # set: unique values
{v: k for k, v in d.items()}         # invert a dict

matrix = [[1, 2], [3, 4], [5]]
[x for row in matrix for x in row]   # [1,2,3,4,5]

展平一层是个合理的天花板。再加一层嵌套或者一个条件,读代码的人就得在脑子里跑一遍。那种时候把循环老老实实写出来。

语法报错、生成器,和停手那条线

改写失败最常见的一种,是把 else 放到了筛选条件后面。Python 会报 SyntaxError: invalid syntax,因为右边的筛选没有 else 这个分支。把整个 if-else 表达式挪到 for 的左边。如果你只想要符合条件的元素,就删掉 else,保留右边那个 if。

[n for n in nums if n % 2 == 0 else 0]
# SyntaxError: invalid syntax

[ n if n % 2 == 0 else 0 for n in nums ]  # choose
[ n for n in nums if n % 2 == 0 ]         # filter

sum(n*n for n in nums)   # generator; no intermediate list
该在哪儿停手
推导式的产物是一个集合。[print(x) for x in items] 会白白分配一个装满 None 的列表;有副作用就用普通循环。另外,一旦出现两个条件、要处理异常,或者得写条注释才能解释那个表达式,也该换回循环。

当 sum、max、any、all 能直接消费这些值时,把方括号去掉,用生成器表达式。这样就不用先存一份临时列表。这么做是为了省内存,不是为了把复杂逻辑硬塞进一行。

📚 本页是 Python 系列中的一篇。通勤路上也能听的完整速成课:10 分钟学会 Python →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.