Python 数据容器详解,list、tuple、str、set、dict 到底怎么选

变量能保存一个值。

但程序真正开始有用,往往是从处理一批数据开始的。

学生名单、商品列表、电影信息、订单记录、接口返回的 JSON,这些都不是一个变量能优雅解决的。

Python 提供了几种非常常用的数据容器:

text 复制代码
list、tuple、str、set、dict

很多初学者的问题不是不会写语法,而是不知道什么时候该用谁。

这篇文章就把它们一次讲清楚。

先看一个真实一点的数据结构

假设我们要表示一部电影:

python 复制代码
movie = {
    "title": "流浪地球",
    "year": 2019,
    "score": 7.9,
    "tags": ["科幻", "冒险", "灾难"],
    "directors": ("郭帆",)
}

print(movie["title"])
print(movie["tags"][0])

这里同时用了字典、列表和元组。

字典描述一部电影的多个属性。

列表保存多个标签。

元组保存不太需要修改的导演信息。

真实项目里的数据经常就是这样嵌套的。

list,最常用的列表

列表有顺序,可以修改,适合保存一组同类数据。

python 复制代码
students = ["小明", "小红", "小刚"]

print(students[0])
print(students[1])

索引从 0 开始。

常用操作:

python 复制代码
students = ["小明", "小红"]

students.append("小刚")
students.insert(1, "小李")
students.remove("小红")

print(students)
print(len(students))

append() 加到末尾。

insert() 插入指定位置。

remove() 按值删除。

len() 获取长度。

列表切片

切片格式:

python 复制代码
items[start:end:step]

示例:

python 复制代码
numbers = [10, 20, 30, 40, 50]

print(numbers[1:4])
print(numbers[:3])
print(numbers[2:])
print(numbers[::2])

输出:

text 复制代码
[20, 30, 40]
[10, 20, 30]
[30, 40, 50]
[10, 30, 50]

规则是包含开始位置,不包含结束位置。

这个规则刚开始有点别扭,但非常统一。range() 也是不包含结束值。

列表遍历

只需要元素:

python 复制代码
scores = [90, 85, 72]

for score in scores:
    print(score)

同时需要索引和元素:

python 复制代码
scores = [90, 85, 72]

for index, score in enumerate(scores):
    print(index, score)

不要为了拿索引强行写:

python 复制代码
scores = [90, 85, 72]

for index in range(len(scores)):
    print(scores[index])

这不是错,但如果你不需要索引,直接遍历元素更清楚。

tuple,固定结构的数据

元组有顺序,但创建后不能修改。

python 复制代码
point = (120.1, 30.2)

print(point[0])
print(point[1])

元组适合保存结构固定的数据,比如坐标、日期片段、函数多个返回值。

python 复制代码
def get_min_max(numbers):
    return min(numbers), max(numbers)


min_value, max_value = get_min_max([3, 8, 1, 9])

print(min_value)
print(max_value)

这里函数返回了两个值。Python 实际上返回的是一个元组,只是我们可以很方便地拆开。

str,字符串也是序列

字符串是文本,也是一种不可变序列。

python 复制代码
word = "Python"

print(word[0])
print(word[1:4])

字符串常用方法:

python 复制代码
text = "  Python,AI,Web  "

print(text.strip())
print(text.lower())
print(text.replace("AI", "Data"))
print(text.split(","))

strip() 去掉两端空白。

lower() 转小写。

replace() 替换文本。

split() 按分隔符切分成列表。

字符串不能直接修改某个字符:

python 复制代码
word = "Python"
# word[0] = "J" 这行会报错

要生成新字符串:

python 复制代码
word = "Python"
new_word = "J" + word[1:]

print(new_word)

set,去重和集合运算

集合不保存重复元素。

python 复制代码
tags = {"Python", "AI", "Python", "Web"}

print(tags)

集合适合做去重:

python 复制代码
names = ["小明", "小红", "小明", "小刚"]
unique_names = set(names)

print(unique_names)

集合运算:

python 复制代码
frontend = {"HTML", "CSS", "JavaScript", "Python"}
backend = {"Python", "Java", "Go"}

print(frontend & backend)
print(frontend | backend)
print(frontend - backend)

& 是交集。

| 是并集。

- 是差集。

集合不适合用索引,因为它不强调顺序。

dict,用键找到值

字典保存键值对。

python 复制代码
user = {
    "name": "小明",
    "age": 18,
    "is_vip": True
}

print(user["name"])

修改和新增:

python 复制代码
user = {"name": "小明", "age": 18}

user["age"] = 19
user["city"] = "杭州"

print(user)

安全读取:

python 复制代码
user = {"name": "小明"}

print(user.get("age", "未知"))

如果直接 user["age"],键不存在会报 KeyError

get() 可以给默认值。

字典遍历

遍历键:

python 复制代码
user = {"name": "小明", "age": 18}

for key in user:
    print(key)

遍历值:

python 复制代码
for value in user.values():
    print(value)

遍历键和值:

python 复制代码
for key, value in user.items():
    print(key, value)

真实开发里,items() 很常用。

容器怎么选

可以按这个流程判断:
#mermaid-svg-a5dXM4AlCpxhlPXs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-a5dXM4AlCpxhlPXs .error-icon{fill:#552222;}#mermaid-svg-a5dXM4AlCpxhlPXs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-a5dXM4AlCpxhlPXs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-a5dXM4AlCpxhlPXs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-a5dXM4AlCpxhlPXs .marker.cross{stroke:#333333;}#mermaid-svg-a5dXM4AlCpxhlPXs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-a5dXM4AlCpxhlPXs p{margin:0;}#mermaid-svg-a5dXM4AlCpxhlPXs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster-label text{fill:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster-label span{color:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster-label span p{background-color:transparent;}#mermaid-svg-a5dXM4AlCpxhlPXs .label text,#mermaid-svg-a5dXM4AlCpxhlPXs span{fill:#333;color:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs .node rect,#mermaid-svg-a5dXM4AlCpxhlPXs .node circle,#mermaid-svg-a5dXM4AlCpxhlPXs .node ellipse,#mermaid-svg-a5dXM4AlCpxhlPXs .node polygon,#mermaid-svg-a5dXM4AlCpxhlPXs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-a5dXM4AlCpxhlPXs .rough-node .label text,#mermaid-svg-a5dXM4AlCpxhlPXs .node .label text,#mermaid-svg-a5dXM4AlCpxhlPXs .image-shape .label,#mermaid-svg-a5dXM4AlCpxhlPXs .icon-shape .label{text-anchor:middle;}#mermaid-svg-a5dXM4AlCpxhlPXs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-a5dXM4AlCpxhlPXs .rough-node .label,#mermaid-svg-a5dXM4AlCpxhlPXs .node .label,#mermaid-svg-a5dXM4AlCpxhlPXs .image-shape .label,#mermaid-svg-a5dXM4AlCpxhlPXs .icon-shape .label{text-align:center;}#mermaid-svg-a5dXM4AlCpxhlPXs .node.clickable{cursor:pointer;}#mermaid-svg-a5dXM4AlCpxhlPXs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-a5dXM4AlCpxhlPXs .arrowheadPath{fill:#333333;}#mermaid-svg-a5dXM4AlCpxhlPXs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-a5dXM4AlCpxhlPXs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-a5dXM4AlCpxhlPXs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a5dXM4AlCpxhlPXs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-a5dXM4AlCpxhlPXs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a5dXM4AlCpxhlPXs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster text{fill:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs .cluster span{color:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-a5dXM4AlCpxhlPXs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-a5dXM4AlCpxhlPXs rect.text{fill:none;stroke-width:0;}#mermaid-svg-a5dXM4AlCpxhlPXs .icon-shape,#mermaid-svg-a5dXM4AlCpxhlPXs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-a5dXM4AlCpxhlPXs .icon-shape p,#mermaid-svg-a5dXM4AlCpxhlPXs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-a5dXM4AlCpxhlPXs .icon-shape .label rect,#mermaid-svg-a5dXM4AlCpxhlPXs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-a5dXM4AlCpxhlPXs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-a5dXM4AlCpxhlPXs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-a5dXM4AlCpxhlPXs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是







要组织数据
是否描述一个对象的多个属性?
dict
是否保存一组有顺序的数据?
是否需要修改?
list
tuple
是否主要为了去重或集合运算?
set
重新检查数据模型

简单判断:

保存多个学生,用列表。

描述一个学生,用字典。

保存坐标,用元组。

处理标签去重,用集合。

处理文本,用字符串。

可变和不可变

列表、字典、集合是可变的。

字符串、元组、数字是不可变的。

看列表:

python 复制代码
items = [1, 2, 3]
items.append(4)

print(items)

原列表被修改了。

看字符串:

python 复制代码
name = "Python"
new_name = name.replace("P", "J")

print(name)
print(new_name)

原字符串没有变,生成了新字符串。

这个区别会影响函数参数、复制、数据共享。现在先记住规则,后面写项目时会经常遇到。

浅拷贝的入门坑

python 复制代码
numbers = [1, 2, 3]
other_numbers = numbers

other_numbers.append(4)

print(numbers)

输出:

text 复制代码
[1, 2, 3, 4]

因为 numbersother_numbers 指向同一个列表。

如果想复制一份:

python 复制代码
numbers = [1, 2, 3]
other_numbers = numbers.copy()

other_numbers.append(4)

print(numbers)
print(other_numbers)

这只是浅拷贝。嵌套结构会更复杂,入门阶段先知道不要随便把可变对象赋来赋去。

完整案例,学生成绩统计

python 复制代码
students = [
    {"name": "小明", "score": 90, "tags": {"认真", "稳定"}},
    {"name": "小红", "score": 85, "tags": {"活跃", "进步"}},
    {"name": "小刚", "score": 72, "tags": {"稳定"}},
]

total_score = 0
passed_students = []
all_tags = set()

for student in students:
    total_score = total_score + student["score"]

    if student["score"] >= 60:
        passed_students.append(student["name"])

    all_tags = all_tags | student["tags"]

average_score = total_score / len(students)

print(f"平均分:{average_score:.2f}")
print(f"及格学生:{passed_students}")
print(f"所有标签:{all_tags}")

这个例子里:

列表保存多个学生。

字典描述单个学生。

集合保存标签并自动去重。

循环负责逐个处理。

这就是容器组合的真实用法。

常见错误

索引越界

python 复制代码
names = ["小明", "小红"]
print(names[2])

列表只有索引 0 和 1,访问 2 会报 IndexError

字典键不存在

python 复制代码
user = {"name": "小明"}
print(user["age"])

会报 KeyError

修复:

python 复制代码
print(user.get("age", "未知"))

修改正在遍历的列表

python 复制代码
numbers = [1, 2, 3, 4]

for number in numbers:
    if number % 2 == 0:
        numbers.remove(number)

这类代码容易跳过元素。

更安全的方式是生成新列表:

python 复制代码
numbers = [1, 2, 3, 4]
odd_numbers = []

for number in numbers:
    if number % 2 != 0:
        odd_numbers.append(number)

print(odd_numbers)

练习

写一个图书统计程序:

  1. 用列表保存多本书。
  2. 每本书用字典表示,包含书名、价格、标签。
  3. 统计所有书的平均价格。
  4. 汇总所有标签并去重。

参考代码:

python 复制代码
books = [
    {"title": "Python 入门", "price": 59.9, "tags": {"编程", "Python"}},
    {"title": "数据分析基础", "price": 69.0, "tags": {"数据", "Python"}},
    {"title": "Web 开发", "price": 79.0, "tags": {"Web", "Python"}},
]

total_price = 0
all_tags = set()

for book in books:
    total_price = total_price + book["price"]
    all_tags = all_tags | book["tags"]

average_price = total_price / len(books)

print(f"平均价格:{average_price:.2f}")
print(f"全部标签:{all_tags}")

参考资料

相关推荐
闵孚龙2 小时前
《PyTorch 深度修炼》Dataset 和 DataLoader:数据如何喂给模型
人工智能·pytorch·python
goldenrolan2 小时前
A公司物料替代测试系统 v1.7:从需求到 exe/apk 的 AI 辅助全链路实践
android·自动化测试·软件测试·python·ai
菜板春2 小时前
jupyter入门-手册-特征探索
python·jupyter
Metaphor6923 小时前
使用 Python 将 PDF 转换为 HTML
python·pdf·html
极光代码工作室3 小时前
基于数据仓库的电商数据分析平台
大数据·hadoop·python·spark·数据可视化
开发小能手-roy3 小时前
StringBuilder vs StringBuffer:2024年还需要线程安全字符串吗?
开发语言·python·安全
AC赳赳老秦3 小时前
用 OpenClaw 搭建服务器故障应急响应系统,自动处理 80% 常见运维故障
android·运维·服务器·python·rxjava·deepseek·openclaw
2601_954706494 小时前
云手机技术详解+Python实战调用|2026高稳云手机平台推荐
开发语言·python·智能手机
chushiyunen4 小时前
java中的路径处理、左右斜杠
java·开发语言·python
jay神4 小时前
基于 FastAPI + Vue 的宠物领养管理系统
前端·vue.js·python·毕业设计·fastapi·宠物