Skip to content

列表快速上手 ​

列表(List)是 Python 中最常用的可变序列类型,用来按顺序存储一组元素。无论是保存一批数据、维护待办事项,还是处理接口返回的数组,都离不开列表。本节将从创建、索引切片、增删改查讲到排序、推导式与常见陷阱。

前置知识

阅读本节前,建议先了解:字符串基本操作,理解序列的索引与切片机制。

基础概念 ​

列表用方括号 [] 创建,元素之间用逗号分隔。它是有序(Ordered)、可变(Mutable)、可重复(Allow Duplicates)、可异构(Heterogeneous)的容器:同一个列表可以同时存放字符串、数字甚至嵌套列表。

特性英文说明
有序Ordered元素按插入顺序保存,可用索引访问
可变Mutable可就地增删改元素
可重复Duplicates Allowed相同元素可以出现多次
异构Heterogeneous可存放不同类型的元素
引用语义Reference Semantics赋值是引用拷贝,不是值拷贝

语法与用法 ​

创建与访问列表的最基本写法:

python
# 最简可运行示例
fruits = ["apple", "banana", "cherry"]

print(fruits)          # 打印整个列表
print(fruits[0])       # 第一个元素
print(fruits[-1])      # 最后一个元素
print(len(fruits))     # 元素个数
text
['apple', 'banana', 'cherry']
apple
cherry
3

详细说明 ​

创建列表的多种方式 ​

python
# 字面量创建
empty: list[int] = []
numbers = [1, 2, 3, 4, 5]
mixed = [1, "two", 3.0, True, None]        # 异构列表
nested = [[1, 2], [3, 4], [5, 6]]          # 嵌套列表

# list() 构造函数
from_string = list("abc")                   # 字符串 -> 字符列表
from_range = list(range(5))                 # range -> 列表
from_tuple = list((1, 2, 3))                # 元组 -> 列表

# 列表推导式(推荐用于生成规律数据)
squares = [n ** 2 for n in range(1, 6)]
evens = [n for n in range(10) if n % 2 == 0]

# 重复列表
zeros = [0] * 5
repeated = ["ab"] * 3

print(empty, numbers)
print(from_string, from_range)
print(squares, evens)
print(zeros, repeated)
text
[] [1, 2, 3, 4, 5]
['a', 'b', 'c'] [0, 1, 2, 3, 4]
[1, 4, 9, 16, 25] [0, 2, 4, 6, 8]
[0, 0, 0, 0, 0] ['ab', 'ab', 'ab']

嵌套列表的乘法陷阱

[[0] * 3] * 3 会得到 3 个指向同一个内层列表的引用,修改其中一个会「连带修改」其他行。应使用推导式创建独立的内层列表。

python
# 错误!三行共享同一个内层列表
wrong = [[0] * 3] * 3
wrong[0][0] = 9
print("错误写法:", wrong)

# 正确:每行都是独立的新列表
right = [[0] * 3 for _ in range(3)]
right[0][0] = 9
print("正确写法:", right)
text
错误写法: [[9, 0, 0], [9, 0, 0], [9, 0, 0]]
正确写法: [[9, 0, 0], [0, 0, 0], [0, 0, 0]]

索引、切片与遍历 ​

列表的索引与切片规则和字符串完全一致:

python
numbers = [10, 20, 30, 40, 50]
# 索引:     0   1   2   3   4
# 负索引:   -5  -4  -3  -2  -1

print(numbers[0], numbers[-1])
print(numbers[1:4], numbers[:3], numbers[2:])      # 各种切片
print(numbers[::-1], numbers[::2])                 # 反转与步长

# 切片赋值:可就地替换一段元素(长度可不同)
numbers[1:4] = [200, 300]
print(numbers)
text
10 50
[20, 30, 40] [10, 20, 30] [30, 40, 50]
[50, 40, 30, 20, 10] [10, 30, 50]
[10, 200, 300, 50]

遍历列表有多种方式,各有适用场景:

python
fruits = ["apple", "banana", "cherry"]

# 方式一:直接遍历元素(最常用)
for fruit in fruits:
    print(fruit)

# 方式二:需要索引时用 enumerate
for index, fruit in enumerate(fruits, start=1):
    print(f"{index}. {fruit}")

# 方式三:用 range + 索引(需要修改元素时)
for i in range(len(fruits)):
    fruits[i] = fruits[i].upper()
print(fruits)
text
apple
banana
cherry
1. apple
2. banana
3. cherry
['APPLE', 'BANANA', 'CHERRY']

增删改查方法 ​

列表方法按用途分类,重点关注哪些是「就地修改(in-place)」的:

方法作用返回值是否原地修改
append(x)末尾追加一个元素None是
extend(iterable)末尾追加多个元素None是
insert(i, x)在索引 i 处插入None是
remove(x)删除第一个值为 x 的元素None是
pop([i])删除并返回索引 i 的元素被删元素是
clear()清空列表None是
index(x)返回首次出现的索引int否
count(x)统计出现次数int否
sort()排序None是
reverse()反转None是
copy()浅拷贝新列表否
python
tasks = ["写文档", "写代码", "测试"]

# 添加
tasks.append("部署")                    # 末尾追加单个
tasks.extend(["监控", "复盘"])           # 末尾追加多个
tasks.insert(0, "需求评审")              # 指定位置插入
print(tasks)

# 删除
tasks.remove("测试")                    # 按值删除
removed = tasks.pop()                   # 弹出末尾元素
first = tasks.pop(0)                    # 弹出指定位置
print(f"弹出:{first}, {removed}")
print(tasks)

# 查询
print(tasks.index("写代码"))
print(tasks.count("写代码"))
text
['需求评审', '写文档', '写代码', '测试', '部署', '监控', '复盘']
弹出:需求评审, 复盘
['写文档', '写代码', '部署', '监控']
1
1

append 与 extend 的区别

append([1, 2]) 把整个列表当作一个元素加入;extend([1, 2]) 把列表展开后逐个加入。这是初学者最常踩的坑之一。

python
# append:整个列表作为单个元素
a = [1, 2, 3]
a.append([4, 5])
print("append 后:", a)

# extend:展开后逐个加入
b = [1, 2, 3]
b.extend([4, 5])
print("extend 后:", b)
text
append 后: [1, 2, 3, [4, 5]]
extend 后: [1, 2, 3, 4, 5]

排序与反转 ​

sort() 就地排序,sorted() 返回新列表。二者都支持 key 与 reverse 参数:

python
numbers = [3, 1, 4, 1, 5, 9, 2, 6]

# sort:就地排序,返回 None
result = numbers.sort()
print(f"返回值:{result},排序后:{numbers}")

# sorted:返回新列表,原列表不变
original = [3, 1, 4, 1, 5]
print(f"原列表:{original},新列表:{sorted(original)}")
print(f"降序:{sorted(original, reverse=True)}")
text
返回值:None,排序后:[1, 1, 2, 3, 4, 5, 6, 9]
原列表:[3, 1, 4, 1, 5],新列表:[1, 1, 3, 4, 5]
降序:[5, 4, 3, 1, 1]

按自定义规则排序使用 key 参数:

python
# 按字符串长度排序
words = ["banana", "apple", "kiwi", "cherry"]
print(sorted(words, key=len))

# 按字典的某个字段排序
users = [
    {"name": "alice", "age": 30},
    {"name": "bob", "age": 25},
    {"name": "cathy", "age": 28},
]
by_age = sorted(users, key=lambda u: u["age"])
for u in by_age:
    print(f"{u['name']:<8} {u['age']}")

# 多级排序:先按年龄升序,年龄相同按姓名
users.sort(key=lambda u: (u["age"], u["name"]))
print([u["name"] for u in users])
text
['kiwi', 'apple', 'banana', 'cherry']
bob      25
cathy    28
alice    30
['bob', 'cathy', 'alice']

深入理解可变性与引用 ​

列表赋值是引用拷贝,这是最容易引发 Bug 的地方。浅拷贝只复制外层,嵌套对象仍被共享,此时需要深拷贝(Deep Copy):

python
import copy

# 赋值是引用拷贝:两个变量指向同一个列表
a = [1, 2, 3]
b = a
b.append(4)
print(f"a = {a},是同一对象:{a is b}")   # a 也被改变了!

# 浅拷贝:创建新列表,但嵌套元素仍共享
c = [1, 2, 3]
d = c.copy()          # 或 c[:] 或 list(c)
d.append(4)
print(f"c = {c},d = {d}")

# 浅拷贝对嵌套结构有隐患
original = [[1, 2], [3, 4]]
shallow = original.copy()
shallow[0][0] = 99
print("浅拷贝后 original:", original)    # 被连带修改

# 深拷贝:完全独立的副本
original2 = [[1, 2], [3, 4]]
deep = copy.deepcopy(original2)
deep[0][0] = 99
print("深拷贝后 original2:", original2)  # 不受影响
text
a = [1, 2, 3, 4],是同一对象:True
c = [1, 2, 3],d = [1, 2, 3, 4]
浅拷贝后 original: [[99, 2], [3, 4]]
深拷贝后 original2: [[1, 2], [3, 4]]

列表推导式 ​

推导式(Comprehension)是 Python 的标志性特性,用一行表达「过滤 + 变换」:

python
# 基础:生成平方数
squares = [n ** 2 for n in range(1, 6)]
print(squares)

# 带条件过滤
evens = [n for n in range(20) if n % 2 == 0]
print(evens)

# 条件表达式(三元)
labels = ["偶数" if n % 2 == 0 else "奇数" for n in range(6)]
print(labels)

# 嵌套循环:笛卡尔积
pairs = [(x, y) for x in range(2) for y in range(2)]
print(pairs)

# 处理字符串列表
words = ["Hello", "WORLD", "Python"]
normalized = [w.lower() for w in words]
print(normalized)

# 提取嵌套结构
matrix = [[1, 2, 3], [4, 5, 6]]
flattened = [n for row in matrix for n in row]
print(flattened)
text
[1, 4, 9, 16, 25]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
['偶数', '奇数', '偶数', '奇数', '偶数', '奇数']
[(0, 0), (0, 1), (1, 0), (1, 1)]
['hello', 'world', 'python']
[1, 2, 3, 4, 5, 6]

推导式家族

推导式不限于列表:{k: v for ...} 生成字典,{x for ...} 生成集合,生成器表达式用 (x for ...)(惰性求值,只遍历一次,适合处理大数据)。

python
# 字典推导式与集合推导式
print({n: n ** 2 for n in range(1, 6)})
print({len(w) for w in ["apple", "kiwi", "pear", "fig"]})   # 集合自动去重

# 生成器表达式:不一次性构建列表,节省内存
total = sum(n ** 2 for n in range(1000))
print(f"0 到 999 的平方和:{total}")
text
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
{3, 4, 5}
0 到 999 的平方和:332833500

实战示例 ​

示例一:待办事项管理器 ​

综合运用增删改查与排序,实现一个小型任务管理工具:

python
from dataclasses import dataclass, field

@dataclass
class Task:
    """待办任务"""
    title: str
    priority: int = 3          # 1 最高,5 最低
    done: bool = False

class TaskManager:
    """待办管理器:支持增删、完成、按优先级排序"""

    def __init__(self) -> None:
        self.tasks: list[Task] = []

    def add(self, title: str, priority: int = 3) -> None:
        """添加任务"""
        self.tasks.append(Task(title, priority))

    def complete(self, title: str) -> bool:
        """按标题标记完成,返回是否成功"""
        for task in self.tasks:
            if task.title == title:
                task.done = True
                return True
        return False

    def remove_done(self) -> int:
        """移除所有已完成任务,返回移除数量"""
        before = len(self.tasks)
        # 用切片赋值实现原地过滤,保留列表对象引用
        self.tasks[:] = [t for t in self.tasks if not t.done]
        return before - len(self.tasks)

    def pending_sorted(self) -> list[Task]:
        """返回未完成任务,按优先级排序"""
        return sorted(
            (t for t in self.tasks if not t.done),
            key=lambda t: t.priority,
        )

manager = TaskManager()
manager.add("修复线上 Bug", priority=1)
manager.add("写周报", priority=4)
manager.add("代码评审", priority=2)

manager.complete("写周报")
removed = manager.remove_done()
print(f"已清理 {removed} 个完成任务")

print("待办(按优先级):")
for task in manager.pending_sorted():
    print(f"  [P{task.priority}] {task.title}")
text
已清理 1 个完成任务
待办(按优先级):
  [P1] 修复线上 Bug
  [P2] 代码评审

示例二:数据分组与统计 ​

列表配合字典完成分组聚合,是数据处理的常见模式:

python
from collections import defaultdict
import statistics

# 原始记录:员工、部门、薪资
records: list[tuple[str, str, int]] = [
    ("alice", "研发", 25000),
    ("bob", "研发", 22000),
    ("cathy", "设计", 18000),
    ("david", "设计", 20000),
    ("eve", "市场", 16000),
    ("frank", "市场", 17000),
    ("grace", "研发", 28000),
]

# 按部门分组
by_dept: dict[str, list[int]] = defaultdict(list)
for _, dept, salary in records:
    by_dept[dept].append(salary)

# 统计每个部门的薪资情况
print(f"{'部门':<8}{'人数':>6}{'平均':>10}{'最高':>10}{'最低':>10}")
for dept, salaries in sorted(by_dept.items()):
    print(
        f"{dept:<8}{len(salaries):>6}"
        f"{statistics.mean(salaries):>10.0f}"
        f"{max(salaries):>10}"
        f"{min(salaries):>10}"
    )

# 找出薪资最高的前两位
top2 = sorted(records, key=lambda r: r[2], reverse=True)[:2]
print("\n薪资 Top2:")
for name, dept, salary in top2:
    print(f"  {name}({dept}){salary:,} 元")
text
部门         人数        平均        最高        最低
市场          2     16500     17000     16000
研发          3     25000     28000     22000
设计          2     19000     20000     18000

薪资 Top2:
  grace(研发)28,000 元
  alice(研发)25,000 元

注意事项 ​

  • 赋值是引用拷贝:b = a 不会复制列表,需用 a.copy()、a[:] 或 list(a)。
  • 浅拷贝不复制嵌套对象:嵌套结构需 copy.deepcopy()。
  • [[0] * 3] * 3 是陷阱:所有行共享同一个内层列表,应使用推导式。
  • append 与 extend 语义不同:一个加单个元素,一个展开追加。
  • sort() 返回 None:x = list.sort() 会让 x 变成 None,这是常见错误。
  • 遍历时删除元素会跳过元素:应遍历副本或倒序删除,或用切片赋值过滤。
  • in 判断是线性查找:大列表频繁判断存在性时改用 set。
  • 列表可哈希元素才能放入 set:列表本身不可哈希,不能作为集合元素。
python
# 错误!遍历时删除会跳过元素
items = [1, 2, 3, 4, 5, 6]
for item in items:
    if item % 2 == 0:
        items.remove(item)
print(f"错误结果:{items}")   # 6 没被删掉

# 正确:遍历副本,或用切片赋值过滤
items2 = [1, 2, 3, 4, 5, 6]
items2[:] = [item for item in items2 if item % 2 != 0]
print(f"正确结果:{items2}")
text
错误结果: [1, 3, 5, 6]
正确结果: [1, 3, 5]

最佳实践 ​

  • 优先使用列表推导式:比 for + append 更简洁且更快。
  • 需要索引时用 enumerate:不要用 range(len(x)) 再取元素(除非要修改)。
  • 用 zip 并行遍历多个列表:for a, b in zip(xs, ys)。
  • 成员判断频繁时改用 set:in 在列表是 O(n),在集合是 O(1)。
  • 用 sorted() 避免副作用:不需要改动原列表时优先用 sorted。
  • 明确区分拷贝语义:浅拷贝用 copy(),深拷贝用 deepcopy()。
  • 为列表元素类型加注解:list[Task] 比裸 list 更能表达意图。

下一节

继续学习:条件判断与循环

参考链接 ​