numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [n for n in numbers if n % 2 == 0]
print(evens)
squares_of_odds = [n * n for n in numbers if n % 2 == 1]
print(squares_of_odds)
第二个可以读作:“对 numbers 中的每个 n 取 n * n,但只在 n 是奇数时。”
等价的循环写法:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
squares_of_odds = []
for n in numbers:
if n % 2 == 1:
squares_of_odds.append(n * n)
print(squares_of_odds)
两种都没问题。推导式更短,而且读过几个之后,你会发现它其实更容易一眼看懂,因为意图就写在一行里。
同时映射和过滤
你可以一边用函数处理值,一边过滤:
words = ["python", "is", "great", "fun"]
long_upper = [w.upper() for w in words if len(w) > 3]
print(long_upper)
对每个长度超过 3 个字母的单词,取它的大写形式。
推导式中的嵌套循环
两个 for 会生成类似笛卡尔积的组合:
suits = ["♠", "♥", "♦", "♣"]
ranks = ["J", "Q", "K", "A"]
deck = [rank + suit for suit in suits for rank in ranks]
print(deck)
顺序和嵌套循环时一样:第一个 for 是外层,第二个是内层。它的读法与等价的缩进循环一样,从左到右。
两层基本就是极限了,再多就不如普通循环好读。如果写到了三层,就改回循环吧。
字典推导式和集合推导式
思路一样,只是换了括号:
numbers = [1, 2, 3, 4, 5]
# Dict comprehension - produces a dict
squares = {n: n * n for n in numbers}
print(squares)
# Set comprehension - produces a set
unique_squares = {n * n for n in [1, -1, 2, -2, 3]}
print(unique_squares)
# Clever but exhausting:
data = [(x, y) for x in range(5) for y in range(5) if (x + y) % 2 == 0 and x != y]
# Clearer as a loop:
data = []
for x in range(5):
for y in range(5):
if (x + y) % 2 == 0 and x != y:
data.append((x, y))
print(data)
结果相同。循环版本是五行而不是一行,但“更长”并不等于“更差”。
几个会反复用到的模式
users = [
{"name": "Ada", "active": True},
{"name": "Boris", "active": False},
{"name": "Ciara", "active": True},
]
# Grab one attribute from each element.
names = [u["name"] for u in users]
print(names)
# Filter and project in one go.
active_names = [u["name"] for u in users if u["active"]]
print(active_names)
# Build a lookup dict keyed by a field.
by_name = {u["name"]: u for u in users}
print(by_name["Ada"])
# Count how many pass a test.
active_count = sum(1 for u in users if u["active"])
print(active_count)