Python 旋风之旅—列表解析/列表推导式(List Comprehensions)

列表推导式(List Comprehensions)

如果您阅读了足够的 Python 代码,最终将遇到被称为列表推导式的简洁高效的构造。 这是 Python 的一项特征,如果您以前没有使用过它,我希望您会爱上它。 它看起来像这样:

[i for i in range(20) if i % 3 > 0]
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

其结果是一个数字列表,其中不包括3的倍数。虽然第一次见到此示例会有些混乱,但是随着对 Python 的熟悉程度的提高,读写列表解析式将成为第二自然的事情。

基本列表推导

列表推导仅是将构建列表的 for 循环压缩为一条简短、易读的行的简单方法。 例如,以下是一个循环,该循环构造了前12个平方整数的列表:

L = []
for n in range(12):
    L.append(n ** 2)
L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

等效的列表推导如下:

[n ** 2 for n in range(12)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

与许多Python语句一样,您几乎可以用通俗的英语朗读该语句的含义:“构造一个由 n 的平方组成的列表,每个 n 最大为 12.”

列表推导的基本语法是 [expr for var in iterable], 其中 expr 是任何有效的表达式,var 是变量名,而 iterable 是任何可迭代的Python对象。

多重迭代

有时,您不仅需要根据一个值,还需要根据两个值来构建列表。 为此,只需在推导式中添加另一个 for 表达式:


[(i, j) for i in range(2) for j in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

注意,第二个for表达式用作内部索引,在结果列表中变化最快。 这种推导式可以在推导式范围内扩展为三个,四个或更多迭代器,尽管有时代码的可读性会受到影响!

条件迭代

您可以通过在表达式的末尾添加条件来进一步控制迭代。 在本节的第一个示例中,我们遍历了从1到20的所有数字,但是略去了 3 的倍数。再次查看此内容,并注意以下构造:

[val for val in range(20) if val % 3 > 0]
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

除非 val 被 3 整除,否则表达式(i%3> 0)的计算结果为True。同样,英语的含义也可以立即读出:“构造一个列表,最大值到 20 为止,如果该值是不可被 3 整除的。 一旦熟悉了它,就比等效的循环语法更容易编写,而且一目了然:

L = []
for val in range(20):
    if val % 3:
        L.append(val)
[1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19]

条件值

如果您使用过 C语言编程,则可能熟悉操作符 ? 启用的单行条件:

int absval = (val < 0) ? -val : val

Python 中也有与此非常相似的结构,它最常用于列表推导,lambda函数以及其他需要简单表达式的地方:

val = -10
val if val >= 0 else -val
10

我们看到,这只是复制了内置函数 abs() 的功能,但是这种构造使您可以在列表推导中做一些非常有趣的事情。 现在这个变得相当复杂,但是您可以执行以下操作:

[val if val % 2 else -val
 for val in range(20) if val % 3]
[1, -2, -4, 5, 7, -8, -10, 11, 13, -14, -16, 17, 19]

请注意在列表推导内的 for 表达式之前的换行符:这在Python中是有效,并且通常是分解长列表推导式以提高可读性的好方法。 看一下该推导式的意义:我们正在做的是构造一个列表,忽略3的倍数,并且对所有 2 的倍数的数字取负数。

一旦了解了动态的列表推导,就可以直接进行其他类型的推导了。 语法基本相同。 唯一的区别是所用括号的类型。

例如,使用花括号可以创建具有集合推导的集合:

{n**2 for n in range(12)}
{0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121}

回想一下,集合是不包含重复项的集。 集合推导遵守此规则,并消除任何重复的项:

{a % 3 for a in range(1000)}
{0, 1, 2}

稍作调整,添加冒号(:) 即可以创建字典推导(dict comprehension):

{n:n**2 for n in range(6)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

最后,如果使用括号而不是方括号,则会得到所谓的生成器表达式:

(n**2 for n in range(12))
<generator object <genexpr> at 0x1027a5a50>

生成器表达式(generator expression)本质上是一种列表推导,其中元素是按需生成的,而不是一次生成的,这里的简单性掩盖了该语言功能的强大之处:我们将在后面进一步探讨。

 

本文来自翻译如下文章,仅用于学习

原文:

https://github.com/jakevdp/WhirlwindTourOfPython/blob/master/11-List-Comprehensions.ipynb

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值