# Python 列表（list）：方法、切片、排序、append、元组与集合

URL: https://skillaria.top/zh/guides/python/spiski-python

列表（list）是 Python 中有序、可变的集合，用方括号书写，例如 [250, 1200, 99]：可以用 append 添加元素，也可以插入、删除、切片和排序。sort 原地排序并返回 None，而 sorted 返回一个新的已排序列表。

Python 中的列表（`list`）是一组有序的任意值，写在方括号中，并且可以修改：可以在末尾添加元素，在中间插入，删除，排序。它是语言中最常用的集合：文件的行、一个月的支出、API 的响应，几乎都从列表开始。下面完整讲解 python list：创建、方法、切片、排序、列表推导式、复制，最后是元组和集合。

## 什么是 Python 列表

列表按你设定的顺序保存元素，并通过从 0 开始的索引访问。同一个列表中可以放不同类型的值，不过实际中通常保存同类数据。

```
amounts = [250, 1200, 99]
print(amounts[0])     # 250 — 第一个元素
print(amounts[-1])    # 99 — 最后一个元素
amounts[1] = 1300     # 列表是可变的
print(len(amounts))   # 3 — 列表长度
```

列表的长度由函数 `len()` 返回。访问不存在的索引会得到 `IndexError: list index out of range`。

## 创建列表

```
empty = []                       # 空列表
also_empty = list()              # 用 list 函数创建，效果相同
nums = [1, 2, 3]
chars = list("abc")              # ['a', 'b', 'c']
digits = list(range(5))          # [0, 1, 2, 3, 4]
zeros = [0] * 4                  # [0, 0, 0, 0]
```

函数 `list()` 可以把任何可迭代对象转换为列表：字符串、`range`、集合、字典的键。

## append 与其他列表方法

`append` 在列表末尾添加一个元素，是 Python 中最常用的方法之一。它原地修改列表，并返回 `None`。

```
amounts = [250, 1200]
amounts.append(450)          # [250, 1200, 450]
amounts.extend([10, 20])     # [250, 1200, 450, 10, 20]
amounts.insert(0, 5)         # [5, 250, 1200, 450, 10, 20]
amounts.remove(1200)         # 删除第一个值为 1200 的元素
last = amounts.pop()         # 20 — 删除并返回最后一个元素
```

常见错误：`a.append([10, 20])` 只会添加一个元素，即嵌套的列表，而不是两个数字。要添加多个元素，应使用 `extend`。

| 方法 | 作用 |
| --- | --- |

| `append(x)` | 在末尾添加 x |

| `extend(iter)` | 添加序列中的所有元素 |

| `insert(i, x)` | 在索引 i 之前插入 x |

| `remove(x)` | 删除第一次出现的 x（不存在则 ValueError） |

| `pop(i=-1)` | 删除并返回索引 i 处的元素 |

| `index(x)` | 第一次出现的索引 |

| `count(x)` | x 出现的次数 |

| `sort()` | 原地排序 |

| `reverse()` | 原地反转 |

| `copy()` | 浅复制 |

| `clear()` | 清空列表 |

按索引或整个范围删除元素也可以使用 `del` 语句：`del a[0]`、`del a[1:3]`。对列表很有用的内置函数有：`len`、`sum`、`min`、`max`、`sorted`、`reversed`、`enumerate`、`zip`。

## Python 中的切片

切片按 `a[start:stop:step]` 的格式取出列表的一部分：从 `start`（包含）到 `stop`（不包含），步长为 `step`。每一部分都可以省略。切片总是返回一个新列表。

```
a = [0, 1, 2, 3, 4, 5]
print(a[1:4])     # [1, 2, 3]
print(a[:2])      # [0, 1] — 前两个
print(a[-2:])     # [4, 5] — 最后两个
print(a[::2])     # [0, 2, 4] — 每隔一个
print(a[::-1])    # [5, 4, 3, 2, 1, 0] — 反转
print(a[:])       # 整个列表的副本
```

与索引不同，切片超出列表范围不会报错：`a[10:20]` 只会返回 `[]`。还可以给切片赋值来替换列表的一部分：`a[1:3] = ["x", "y", "z"]`。

### 字符串切片

切片对所有序列都适用，包括字符串和元组：

```
s = "Python 3.15"
print(s[:6])      # Python
print(s[-4:])     # 3.15
print(s[::-1])    # 51.3 nohtyP
```

字符串不能通过切片修改——字符串是不可变的，切片会创建一个新字符串。

## 列表排序：sort 与 sorted

这是新手最容易混淆的地方。`sort` 方法在列表内部重新排列元素，并返回 `None`。函数 `sorted` 不改动原列表，而是返回一个新的已排序列表。

```
amounts = [250, 1200, 99]
amounts.append(450)
print(sorted(amounts))     # [99, 250, 450, 1200] — 新副本
print(amounts)             # [250, 1200, 99, 450] — 原列表不变

result = amounts.sort()    # 原地排序
print(result, amounts)     # None [99, 250, 450, 1200]
```

这就是经典的“为什么我得到 None”问题：`a = a.sort()` 会把列表覆盖成 `None`。应该写 `a.sort()`，或者 `a = sorted(a)`。

### 关键字 key 与逆序

两者都接受 `key` 和 `reverse` 参数。`key` 是一个函数，元素将根据它的结果进行比较。

```
words = ["coffee", "Taxi", "subscription"]
print(sorted(words, key=len))               # ['Taxi', 'coffee', 'subscription']
print(sorted(words, key=str.lower))         # 不区分大小写
print(sorted([3, 1, 2], reverse=True))      # [3, 2, 1]

expenses = [("餐饮", 650), ("电影", 120), ("打车", 300)]
expenses.sort(key=lambda e: e[1])           # 按金额排序
```

Python 的排序是稳定的：键相同的元素保持原来的相对顺序。另一个区别在于适用范围：`sorted` 可以用于任何序列（字符串、字典、集合），而 `sort` 只有列表才有。

## 反转列表

有三种方式，行为各不相同：

- `a.reverse()` — 原地反转，返回 `None`；
- `a[::-1]` — 生成一个新的反转列表；
- `reversed(a)` — 惰性迭代器，适合在循环中使用：`for x in reversed(a):`。

## 遍历列表

```
items = ["咖啡", "地铁", "电影"]
for item in items:
    print(item)

for i, item in enumerate(items, start=1):
    print(i, item)          # 1 咖啡，2 地铁，3 电影

print("电影" in items)      # True — 检查是否包含
```

不要在遍历列表的同时删除其中的元素，否则会漏掉一些元素。应该用列表推导式生成一个新列表，或者遍历副本 `a[:]`。

## 列表推导式（list comprehension）

列表推导式可以用一行代码构造新列表：表达式、循环以及可选的条件。

```
squares = [n * n for n in range(6)]          # [0, 1, 4, 9, 16, 25]
big = [a for a in [250, 1200, 99] if a > 200]  # [250, 1200]
names = [s.strip().title() for s in [" alice ", "bob"]]   # ['Alice', 'Bob']
```

列表推导式通常比带 `append` 的循环更快，也更易读。但如果逻辑无法放进一行清晰的代码中，普通的循环更好。

## 列表的合并、相加与相减

```
a = [1, 2, 3]
b = [3, 4]
print(a + b)       # [1, 2, 3, 3, 4] — 新列表
a += b             # 相当于 a.extend(b)
print([*a, *b])    # 解包到新列表中
```

Python 中没有用 `-` 来做列表相减的运算符。要从一个列表中去掉另一个列表的元素，可以使用推导式：`[x for x in a if x not in set(b)]`。列表的交集最方便的方法是借助集合：`set(a) & set(b)`（这会丢失顺序和重复元素）。

## 嵌套列表与二维列表

列表的列表是保存表格或矩阵的简单方式：

```
matrix = [[1, 2, 3], [4, 5, 6]]
print(matrix[1][2])     # 6
grid = [[0] * 3 for _ in range(2)]   # 正确
bad = [[0] * 3] * 2                  # 陷阱：两个引用指向同一个列表
bad[0][0] = 9
print(bad)              # [[9, 0, 0], [9, 0, 0]]
```

## 列表解包

```
first, second, third = [10, 20, 30]
head, *rest = [1, 2, 3, 4]      # head=1, rest=[2, 3, 4]
print(*["a", "b"], sep=", ")    # a, b — 不带括号打印列表元素
```

如果变量数量与列表长度不一致，会得到 `ValueError`——这时星号变量就能派上用场。

## 复制列表

`b = a` 并不会复制列表，而是给同一个对象再贴上一个标签：通过 `b` 做的修改在 `a` 中也能看到。独立的副本需要显式创建：`a.copy()`、`list(a)` 或 `a[:]`。对于嵌套数据，这还不够——内层列表依然共享，需要使用 `copy.deepcopy(a)`。

```
import copy
a = [[1, 2], [3]]
b = a.copy()
b[0].append(99)
print(a)                 # [[1, 2, 99], [3]] — 嵌套列表是共享的
c = copy.deepcopy(a)     # 完全独立的副本
```

## 元组：不可变的列表

元组（`tuple`）与列表相似，但创建后不能修改。这向读者传达了一个明确的信号：这是一条由固定字段组成的记录，而不是可以增长的集合。元组很容易解包，函数通常正是用元组返回多个值。

```
expense = (250, "咖啡")
amount, item = expense
expense[0] = 300
# TypeError: 'tuple' object does not support item assignment
```

由不可变值组成的元组是可哈希的，因此可以用作字典的键。只有一个元素的元组要写逗号：`(5,)`。

## 集合：只保存唯一值

集合（`set`）只保存唯一的值，并且不记录顺序。它是去重以及检查“是否存在”的最快方法，还支持交集、并集和差集。

```
jan = {"餐饮", "打车", "电影"}
feb = {"餐饮", "订阅"}
print(jan & feb)    # {'餐饮'}
print(feb - jan)    # {'订阅'}
unique = list(dict.fromkeys([3, 1, 3, 2]))   # [3, 1, 2] — 去重且保持顺序
empty = set()       # {} 是空字典！
```

## 如何选择集合类型

| 任务 | 集合类型 |
| --- | --- |

| 需要顺序并且可以修改 | `list` |

| 固定的记录 | `tuple` |

| 按键查找 | `dict` |

| 唯一性，检查是否存在 | `set` |

| 不可变的设置 | `frozendict`（Python 3.15） |

`x in list` 会逐个比较元素，而 `x in set` 几乎是瞬间完成的。如果在循环中多次检查一个大列表中是否包含某值，把它转换为集合。

## 小结

Python 列表是有序、可变的集合：`append` 和 `extend` 用于添加，`pop` 和 `remove` 用于删除，切片 `a[start:stop:step]` 用于截取部分，`sort` 原地排序并返回 `None`，而 `sorted` 返回新列表。复制要显式进行；固定的记录使用元组，唯一的值使用集合。列表、元组、字典和集合在课程《Python 3.15：从新手到专家》中都有实践讲解。

## FAQ

**Python 列表和数组有什么区别？**

Python 中没有其他语言意义上的内置数组，它的角色由列表承担，列表可以同时保存不同类型的值。紧凑的数值数组可以使用 array 模块或 NumPy 库。

**如何查找列表中某个元素的索引？**

方法 a.index(x) 返回第一次出现的索引，如果元素不存在则抛出 ValueError。因此调用前最好先检查 x in a。

**如何在保持顺序的情况下去除列表中的重复项？**

使用 list(dict.fromkeys(a))：字典的键是唯一的，并且保持插入顺序。list(set(a)) 也能去重，但不保留顺序。

**如何把字符串列表合并为一个字符串？**

使用字符串的 join 方法：", ".join(["a", "b", "c"]) 得到 "a, b, c"。所有元素必须是字符串，数字要先用 map(str, a) 转换。

**列表中可以放不同类型的元素吗？**

可以，一个列表可以同时包含数字、字符串、其他列表以及任何对象。但对这样的列表排序通常需要提供 key 参数，否则比较数字和字符串会引发 TypeError。


---
Source: Skillaria.Top (https://skillaria.top)
