小能豆

理解 Python 中的列表推导

py

这个例子:

>>> vec = [[1,2,3], [4,5,6], [7,8,9]]

>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

我无法理解这一点,所以我做了一些实验:

>>> [num for elem in vec]
[9, 9, 9]

>>> [num for elem in (vec for num in elem)]
[9, 9, 9]

现在我更加困惑了!

我应该按照什么顺序阅读列表推导?


我确定我没有num在任何地方定义值为 9 的变量。

python

输出:

Python 2.7.10 (default, Oct 23 2015, 19:19:21)
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

REPL会话:

>>> num
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'num' is not defined

>>> vec = [[1,2,3], [4,5,6], [7,8,9]]

>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]

>>> [num for elem in vec]
[9, 9, 9]

>>> [num for elem in (vec for num in elem)]
[9, 9, 9]

阅读 21

收藏
2024-12-01

共1个答案

小能豆

The confusion you’re experiencing comes from how list comprehensions work, especially with nested ones. Let’s go through each case to clarify the behavior:

1. First Case:

vec = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[num for elem in vec for num in elem]

This list comprehension flattens the nested list. Here’s how it works:
- for elem in vec: Iterates through each sublist (like [1, 2, 3]).
- for num in elem: For each elem, it iterates through its elements (like 1, 2, 3).
- This results in a flattened list where all the numbers are collected: [1, 2, 3, 4, 5, 6, 7, 8, 9].

So, the order of the loops is important, and the comprehension works from left to right—first iterating over the outer list (vec), and then over each inner list (elem).

2. Second Case:

[num for elem in vec]

Here, you’re only iterating over vec, but you haven’t specified what to extract from each elem. Since you’re not doing anything with elem, this doesn’t work as expected. In fact, Python will just use elem as is, so it defaults to using the last element of vec for num. Since vec ends with [7, 8, 9], that’s what is returned:

[9, 9, 9]

This happens because Python is just placing the value of elem in num for each iteration, which happens to be the last element of the outer list, [7, 8, 9].

3. Third Case:

[num for elem in (vec for num in elem)]

This is even more confusing. The expression (vec for num in elem) is a generator expression that does not make sense here. Essentially, it just generates vec over and over again without any useful transformation. Because of this, the result will again be just the last item of vec, which is [7, 8, 9], and Python places num as the last element of each iteration, resulting in [9, 9, 9].

Correct Understanding of List Comprehension:

List comprehensions are evaluated from left to right:
1. The first for iterates through the outer list (in your case, vec).
2. The second for iterates through each sublist (in your case, the elements inside each sublist).

So, for example, the correct list comprehension to flatten vec would be:

[num for elem in vec for num in elem]

This iterates through each sublist (elem) inside vec, and for each elem, it iterates through each number (num).

How to think about it:

  • Order of loops matters. The first for refers to iterating over the outer structure (in this case, vec), and the second for refers to iterating over the inner structures (like [1, 2, 3]).
  • If you try to use a single for like in the second example, it will just give the last element of the outer list, not the individual elements of the inner list.

Let me know if you’d like further clarification on how list comprehensions work!

2024-12-01