0x02 中提到的 map
/filter
方法可以通过简化的语法快速构建我们需要的列表(或其它可迭代对象),与它们功能相似的,Python 还提供列表推导(List Comprehension)的语法。最初学 Python 的时候,我只是把这种语法当做一种语法糖,可以用来快速构建特定的列表,后来学习 Haskell 的时候才知道这种形式叫做 List Comprehension(中文我好像没有找到固定的翻译,有翻译成列表速构、列表解析之类的,但意思上都是在定义列表结构的时候按照一定的规则进行推导,而不是穷举所有元素)。
这种列表推导与数学里面集合的表达形式有些相似,例如$[0, 10)$之间偶数集合可以表示为:
$$\left\{x\ |\ x \in N, x \lt 10, x\ mod\ 2\ ==\ 0\right\}$$翻译成 Python 表达式为:
In [1]:
evens = [x for x in range(10) if x % 2 == 0]
print(evens)
这与filter
效果一样:
In [2]:
fevens = filter(lambda x: x % 2 == 0, range(10))
print(list(fevens) == evens)
同样,列表推导也可以实现map
的功能:
In [3]:
squares = [x ** 2 for x in range(1, 6)]
print(squares)
msquares = map(lambda x: x ** 2, range(1, 6))
print(list(msquares) == squares)
相比之下,列表推导的语法更加直观,因此更 Pythonic 的写法是在可以用列表推导的时候尽量避免map
/filter
。
除了上面简单的迭代、过滤推导之外,列表推导还支持嵌套结构:
In [4]:
cords = [(x, y) for x in range(3) for y in range(3) if x > 0]
print(cords)
# 相当于
lcords = []
for x in range(3):
for y in range(3):
if x > 0:
lcords.append((x, y))
print(lcords == cords)
In [5]:
dns = {domain : ip
for domain in ["github.com", "git.io"]
for ip in ["23.22.145.36", "23.22.145.48"]}
print(dns)
names = {name for name in ["ana", "bob", "catty", "octocat"] if len(name) > 3}
print(names)
0x01中提到的生成器(Generator),除了在函数中使用 yield
关键字之外还有另外一种隐藏方法,那就是对元组(Tuple)使用列表推导:
In [6]:
squares = (x for x in range(10) if x % 2 == 0)
print(squares)
print(next(squares))
next(squares)
for i in squares:
print(i)