我有以下代码:
[x**2 for x in range(10)]
当我在Python Shell中运行它时,它返回:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
我已经搜索了,这似乎被称为列表理解,但它是如何工作的?
答案 0 :(得分:76)
列表推导提供了创建列表的简明方法。常见的应用是创建新的列表,其中每个元素是应用于另一个序列的每个成员或可迭代的一些操作的结果,或者创建满足特定条件的那些元素的子序列。
关于你的问题,列表理解与下面的" plain"相同。 Python代码:
>>> 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
你听说过nested list comprehension吗?您可以将两个或更多>>> [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 x in [[1, 2, 3], [4, 5, 6]]
。
警告:您需要先将for i in x
放在 >>> [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}
我们还有设置理解, dict comprehensions 和生成器表达式。
设置理解和列表推导基本相同,但前者返回集而不是列表:
>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}
它与:
相同{key: value for key, value in ...}
dict comprehension 看似集合理解,但它使用{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>
是否会提供元组?不!它是generator expression。返回生成器:
>>> 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(i**2 for i in range(5))
30
。例如,sum()
:
src
相关(关于发电机):Understanding Generators in Python。
答案 1 :(得分:7)
有列表,字典和集合理解,但没有元组理解(尽管可以探索&#34;生成器表达式&#34;)。
它们解决了Python中的传统循环是语句(不返回任何内容)而不是返回值的表达式的问题。
它们不是每个问题的解决方案,可以重写为传统循环。当需要维持状态时,它们会变得尴尬。在迭代之间更新。
它们通常包括:
[<output expr> <loop expr <input expr>> <optional predicate expr>]
但可以用许多有趣和奇怪的方式扭曲。
它们可以类似于传统的map()
和filter()
操作,这些操作仍然存在于Python中并继续使用。
如果做得好,他们的满意度很高。
答案 2 :(得分:2)
如果您希望以更直观的方式弄清楚正在发生的事情,那么这可能会有所帮助:
# 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]
答案 3 :(得分:2)
最近(关于其他SO问题以及来自同事的信息),我对列表理解的工作方式感到困惑。少量的数学教育可以帮助理解为什么这样的语法,以及列表理解的真正含义。
最好将列表推导视为集合/集合的谓词,就像我们在数学中使用集合生成器表示法一样。实际上,这种感觉对我来说很自然,因为我持有数学本科学位。但是忘了我吧,Guido van Rossum(Python的发明者)拥有数学硕士学位并且具有数学背景。
以下是设置构建器符号的工作原理(非常基础):
因此,此集生成器符号表示严格为正数(即[1,2,3,4,...]
)的数字集。
1)集合构建器表示法中的谓词过滤器仅指定我们要保留的项,而列表理解谓词执行相同的事情。您不必为省略项而添加特殊的逻辑,除非谓词包括它们,否则将省略它们。空谓词(即末尾无条件)包括给定集合中的所有项。
2)集构建器符号中的谓词过滤器位于末尾,列表理解也是如此。(有些)初学者认为类似[x < 5 for x in range(10)]
的东西会给他们列表{{1 }},实际上它输出[0,1,2,3,4]
。我们得到输出[True, True, True, True, True, False, False, False, False, False]
,因为我们要求Python对[True, True, True, True, True, False, False, False, False, False]
中的所有项评估x < 5
。没有谓词意味着我们从集合中获得了所有内容(就像集合生成器符号一样)。
如果在使用列表推导功能时将设置的构建器符号保留在脑海中,则它们会更容易被吞噬。
HTH!
答案 4 :(得分:0)
简介
列表理解是在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'>
有关EXPRESSION的更多信息
表达式可以是任何可减少为值的值:
n ** 2 + 3 * n + 1
f(n)
作为变量的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允许您编写列表以外的其他类型的理解: