我有以下的代码:
[x ** 2 for x in range(10)]
当我在Python shell中运行它时,它会返回:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我搜索了一下,似乎这被称为列表推导式,类似地还有集合/字典推导式和生成器表达式。但是它是如何工作的呢?
我搜索过后发现,这种语法结构被称为列表推导式,类似的还有集合/字典推导式和生成器表达式。但是它们是如何运作的呢?
我有以下的代码:
[x ** 2 for x in range(10)]
当我在Python shell中运行它时,它会返回:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我搜索了一下,似乎这被称为列表推导式,类似地还有集合/字典推导式和生成器表达式。但是它是如何工作的呢?
我搜索过后发现,这种语法结构被称为列表推导式,类似的还有集合/字典推导式和生成器表达式。但是它们是如何运作的呢?
列表推导式提供了一种简洁的方法来创建列表。常见的应用是创建新列表,其中每个元素都是应用于另一个序列或可迭代对象的每个成员的某些操作的结果,或者创建满足某些条件的这些元素的子序列。
>>> l = []
>>> for x in range(10):
... l.append(x**2)
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如何用一行代码来写?嗯...我们可以...可能会用到 map()
和 lambda
:
>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
但是使用列表推导式不是更清晰简单吗?
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
x
做任何事情。不仅仅是x**2
。例如,运行x
的一个方法:>>> [x.strip() for x in ('foo\n', 'bar\n', 'baz\n')]
['foo', 'bar', 'baz']
或者将x
作为另一个函数的参数:
>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]
x
作为dict
对象的键来使用。例如,看下面这个例子:>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']
怎么样组合一下?
>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [int(d[x].rstrip('0')) for x in ['foo', 'baz']]
[1, 3]
等等。
您也可以在列表推导式中使用if
或if...else
。例如,您只想要range(10)
中的奇数。您可以这样做:
>>> l = []
>>> for x in range(10):
... if x%2:
... l.append(x)
>>> l
[1, 3, 5, 7, 9]
>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]
if...else
三元表达式,你需要将if ... else ...
放在x
后面,而不是range(10)
后面。>>> [i if i%2 != 0 else None for i in range(10)]
[None, 1, None, 3, None, 5, None, 7, None, 9]
你听说过嵌套列表推导式吗?你可以在一个列表推导式中放置两个或多个for
。例如:
>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x]
[1, 2, 3, 4, 5, 6]
>>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i]
[1, 2, 3, 4, 5, 6]
for x in [[1, 2, 3], [4, 5, 6]]
,它给出了[1, 2, 3]
和[4, 5, 6]
。然后,for i in x
给出了1
、2
、3
和4
、5
、6
。
警告:你总是需要在for i in x
之前放置for x in [[1, 2, 3], [4, 5, 6]]
。>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'x' is not defined
>>> {x for x in [1, 1, 2, 3, 3, 1]}
{1, 2, 3}
它和这个是一样的:
>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}
一个字典推导式看起来像一个集合推导式,但它使用{key: value for key, value in ...}
或{i: i for i in ...}
而不是{i for i in ...}
。
例如:
>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
它等于:
>>> d = {}
>>> for i in range(5):
... d[i] = i**2
>>> d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
(i for i in range(5))
是一个生成器表达式,不是元组。它返回一个生成器,详情请参考生成器表达式。
>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>
这与以下内容相同:
>>> def gen():
... for i in range(5):
... yield i
>>> gen()
<generator object gen at 0x7f5270380db0>
而且你可以将它用作生成器:
>>> gen = (i for i in range(5))
>>> next(gen)
0
>>> next(gen)
1
>>> list(gen)
[2, 3, 4]
>>> next(gen)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
[]
。例如,sum()
:>>> sum(i**2 for i in range(5))
30
相关(关于生成器):理解Python中的生成器。
x if cond else y
实际上与列表推导式没有任何特定关系 - 任何有效的表达式都可以在列表推导式中使用 - 三元表达式只是 Python 表达式的众多之一。 - AChampion[i for i in x if i else y]
,但它并不起作用。经过一些研究,我明白我必须使用 [i if i else y for i in x]
。所以我认为如果我在这里提到它,那么其他人就可以避免我之前遇到的问题。 - Remi GuanPython中有列表、字典和集合推导式,但没有元组推导式(不过可以尝试“生成器表达式”)。
它们解决了传统循环在Python中是语句(不返回任何内容)而不是表达式的问题,而表达式可以返回值。
它们并非解决所有问题的万能药,并且可以重写为传统循环。当需要在迭代之间维护和更新状态时,它们变得笨拙。
它们通常由以下部分组成:
[<output expr> <loop expr <input expr>> <optional predicate expr>]
但是可以以许多有趣和奇怪的方式扭曲它们。
它们可以类比于传统的map()
和filter()
操作,这些操作仍然存在于Python中并继续使用。
当做得好时,它们具有很高的满意度。
如果你更喜欢通过视觉方式了解正在发生的事情,那么也许这会有所帮助:
# for the example in the question...
y = []
for x in range(10):
y += [x**2]
# is equivalent to...
y = [x**2 for x in range(10)]
# for a slightly more complex example, it is useful
# to visualize where the various x's end up...
a = [1,2,3,4]
b = [3,4,5,6]
c = []
for x in a:
if x in b:
c += [x]
# \ \ /
# \ _____\______/
# \ / \
# \/ \
# /\ \
# / \ \
# / \ \
c = [x for x in a if x in b]
print(c)
...生成输出[3, 4]
因此,这个集合构建符号表示的是严格为正数的数字集合(即[1,2,3,4,...]
)。
1)在集合构建符号中,谓词过滤器只指定我们想要保留的项,列表推导谓词也是同样的道理。您不必包含特殊逻辑来省略项目,除非谓词包括该项目,否则它们将被省略。空谓词(即末尾没有条件)会包括给定集合中的所有项。
2) 在集合构建符号中,谓词过滤器放在最后,在列表推导式中也是如此。 一些初学者认为像[x < 5 for x in range(10)]
这样的表达式会给他们一个列表[0,1,2,3,4]
,但实际上它输出的是[True, True, True, True, True, False, False, False, False, False]
。我们得到[True, True, True, True, True, False, False, False, False, False]
的输出是因为我们要求Python对range(10)
中的所有项目都评估x < 5
。没有谓词意味着我们从集合中获取所有内容(就像在集合构建符号中一样)。
如果你在使用列表推导式时将集合构建符号记在脑海中,它们会更容易理解。
希望有所帮助!
介绍
列表推导式是在Python中创建列表的一种高级、声明性方法。它们的主要优点是可读性和可维护性。许多人发现它们非常易读,即使以前从未见过它们的开发人员通常也能猜出其含义。
# Snippet 1
squares = [n ** 2 for n in range(5)]
# Snippet 2
squares = []
for n in range(5):
squares.append(n ** 2)
这两段代码将生成squares
等于[0, 1, 4, 9, 16]
。
需要注意的是,在第一段代码中,你所输入的是声明要创建何种类型的列表,而第二段代码则指定了如何创建列表。这就是为什么推导式具有高级和声明性的特点。
语法
[EXPRESSION for VARIABLE in SEQUENCE]
EXPRESSION
是 Python 语言中的任何表达式,但通常情况下要使用一些变量。这个变量在 VARIABLE
字段中被声明。 SEQUENCE
定义了变量枚举的值的来源。
考虑代码片段 1,[n ** 2 for n in range(5)]
:
EXPRESSION
是 n ** 2
VARIABLE
是 n
SEQUENCE
是 range(5)
请注意,如果检查 squares
的类型,您会发现列表推导只是一个普通的列表:
>>> type(squares)
<class 'list'>
关于表达式
表达式可以是任何能够简化为值的东西:
n ** 2 + 3 * n + 1
n
的函数调用,如f(n)
s[::-1]
bar.foo()
以下是一些示例:
>>> [2 * x + 3 for x in range(5)]
[3, 5, 7, 9, 11]
>>> [abs(num) for num in range(-5, 5)]
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal.upper() for animal in animals]
['DOG', 'CAT', 'LION', 'TIGER']
筛选:
最终列表中元素的顺序由SEQUENCE
的顺序确定。但是,您可以通过添加if
子句来过滤掉元素:
[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]
CONDITION
是一个表达式,其评估结果为 True
或 False
。从技术上讲,条件不一定要依赖于 VARIABLE
,但通常会使用它。
例如:
>>> [n ** 2 for n in range(5) if n % 2 == 0]
[0, 4, 16]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal for animal in animals if len(animal) == 3]
['dog', 'cat']
另外,请记住,Python 允许您编写除列表之外的其他类型的推导式: