外观
Python 常用数据类型:str、list、tuple、dict、set 详解
刚学 Python 时,最容易反复碰到的五种内置类型,就是 str、list、tuple、dict 和 set。
它们几乎无处不在:
- 读一行文本,得到的是
str - 保存一组元素,常常用
list - 不希望内容被修改时,会考虑
tuple - 做键值映射时,用
dict - 去重、做集合运算时,用
set
表面上看,这五种类型都像是在“装数据”,但它们的设计目标并不一样。如果一开始没有把它们的定位和方法搞清楚,后面写代码时就很容易混用,甚至写出一些效率很差、可读性也不好的代码。
这篇文章想做两件事:
- 先讲清楚这五种类型分别适合干什么;
- 再系统梳理它们最常用的方法,以及这些方法到底是“原地修改”还是“返回新对象”。
先有一个整体印象
可以先用一张表把五种类型的大轮廓记住:
| 类型 | 可变吗 | 有序吗 | 可重复吗 | 典型用途 |
|---|---|---|---|---|
str | 不可变 | 有序 | 可以 | 文本处理 |
list | 可变 | 有序 | 可以 | 动态序列 |
tuple | 不可变 | 有序 | 可以 | 固定记录、不可变序列 |
dict | 可变 | 按插入顺序保序 | key 不可重复 | 键值映射 |
set | 可变 | 无序 | 不可重复 | 去重、集合运算 |
这里最值得先记住的一点是:
str和tuple是不可变的;list、dict、set是可变的。
这件事会直接影响它们的方法设计。例如:
list.append()会原地修改列表;- 但字符串不会“原地追加”,而是返回一个新的字符串。
一、字符串 str
字符串本质上是一个不可变的字符序列。所谓不可变,是指字符串一旦创建,就不能直接修改其中某个字符。
例如下面这样是不行的:
s = "hello"
# s[0] = "H" # TypeError如果想“修改”字符串,实际上是在创建一个新字符串。
1. 常见创建方式
s1 = 'hello'
s2 = "world"
s3 = """multi
line"""2. 常见基本操作
s = "python"
len(s) # 6
s[0] # 'p'
s[-1] # 'n'
s[1:4] # 'yth'
"py" in s # True
s + "3" # 'python3'
s * 2 # 'pythonpython'3. 大小写相关方法
lower()
把字符串转成小写。
"Hello".lower() # 'hello'upper()
把字符串转成大写。
"Hello".upper() # 'HELLO'capitalize()
首字母大写,其余小写。
"python".capitalize() # 'Python'title()
把每个单词首字母变成大写。
"hello world".title() # 'Hello World'swapcase()
大小写互换。
"Hello".swapcase() # 'hELLO'casefold()
比 lower() 更激进的大小写折叠,常用于不区分大小写的比较。
4. 查找与判断方法
find(sub[, start[, end]])
查找子串,找到返回下标,找不到返回 -1。
"banana".find("na") # 2rfind()
从右边开始找,但返回的仍然是正常下标。
index()
和 find() 类似,但找不到时会抛 ValueError。
"banana".index("na") # 2rindex()
从右边找,找不到也会报错。
count(sub)
统计子串出现次数。
"banana".count("a") # 3startswith(prefix) / endswith(suffix)
判断是否以某个前缀或后缀开头/结尾。
"report.pdf".endswith(".pdf") # True5. 替换与分割
replace(old, new[, count])
替换子串,返回新字符串。
"I like cats".replace("cats", "dogs") # 'I like dogs'split(sep=None, maxsplit=-1)
分割字符串,返回列表。
"a,b,c".split(",") # ['a', 'b', 'c']不传参数时,按任意空白字符切分。
rsplit()
从右边开始切分。
splitlines()
按行切分。
"a\nb\nc".splitlines() # ['a', 'b', 'c']join(iterable)
把一个可迭代对象里的字符串连接起来。这个方法很重要,而且它属于分隔符字符串,而不是列表。
"-".join(["2026", "05", "04"]) # '2026-05-04'6. 去空白与对齐
strip([chars])
去掉两端空白字符,或去掉两端指定字符。
" hello ".strip() # 'hello'lstrip() / rstrip()
分别去左边或右边。
center(width[, fillchar])
居中对齐。
ljust(width[, fillchar]) / rjust(width[, fillchar])
左对齐或右对齐。
zfill(width)
左侧补零。
"42".zfill(5) # '00042'7. 判断类方法
这些方法常用于输入校验:
isalpha():是否全是字母isdigit():是否全是数字isalnum():是否全是字母或数字isspace():是否全是空白字符islower():是否全是小写isupper():是否全是大写istitle():是否符合标题格式
"123".isdigit() # True
"abc".isalpha() # True8. 格式化
format()
"name: {}, age: {}".format("Tom", 20)f-string
严格说不是 str 方法,但在实际 Python 代码里更常用。
name = "Tom"
age = 20
f"name: {name}, age: {age}"9. str 使用时最容易犯的错
第一,字符串不可变,所以很多方法都不会修改原字符串:
s = " hello "
s.strip()
print(s) # 仍然是 " hello "要写成:
s = s.strip()第二,拼接大量字符串时,不要在循环里反复 +,通常更适合先放进列表,再用 join()。
二、列表 list
列表是 Python 里最常用的可变有序序列。如果你需要一个能动态增删改的容器,通常第一反应就是 list。
1. 创建方式
nums = [1, 2, 3]
empty = []
chars = list("abc") # ['a', 'b', 'c']2. 常见基本操作
nums = [10, 20, 30]
len(nums) # 3
nums[0] # 10
nums[-1] # 30
nums[1:] # [20, 30]
20 in nums # True
nums + [40] # [10, 20, 30, 40]
nums * 2 # [10, 20, 30, 10, 20, 30]3. 添加元素的方法
append(x)
在末尾追加一个元素。
nums = [1, 2]
nums.append(3) # [1, 2, 3]extend(iterable)
把一个可迭代对象中的元素逐个追加进去。
nums = [1, 2]
nums.extend([3, 4]) # [1, 2, 3, 4]append([3, 4]) 和 extend([3, 4]) 的区别一定要分清:
a = [1, 2]
a.append([3, 4]) # [1, 2, [3, 4]]
b = [1, 2]
b.extend([3, 4]) # [1, 2, 3, 4]insert(i, x)
在指定位置插入元素。
nums = [1, 3]
nums.insert(1, 2) # [1, 2, 3]4. 删除元素的方法
remove(x)
删除第一个值等于 x 的元素。
nums = [1, 2, 2, 3]
nums.remove(2) # [1, 2, 3]pop([i])
按下标弹出元素;不传参数时默认弹出最后一个。
nums = [10, 20, 30]
nums.pop() # 30
nums.pop(0) # 10clear()
清空列表。
del
del 不是方法,而是语句,但和列表一起使用非常多。
nums = [1, 2, 3, 4]
del nums[1:3] # [1, 4]5. 查找与统计
index(x[, start[, end]])
返回元素第一次出现的位置。
count(x)
统计元素出现次数。
[1, 2, 2, 3].count(2) # 26. 排序与反转
sort(key=None, reverse=False)
原地排序,非常常用。
nums = [3, 1, 2]
nums.sort() # nums 变成 [1, 2, 3]如果想按自定义规则排序,可以配合 key:
words = ["ccc", "a", "bb"]
words.sort(key=len) # ['a', 'bb', 'ccc']sorted(iterable, key=None, reverse=False)
这不是 list 方法,而是内置函数。它会返回新列表,不修改原对象。
nums = [3, 1, 2]
new_nums = sorted(nums)reverse()
原地反转列表顺序。
nums = [1, 2, 3]
nums.reverse() # [3, 2, 1]reversed(iterable)
也不是 list 方法,而是返回一个迭代器。
7. 复制相关
copy()
浅拷贝。
a = [1, 2, 3]
b = a.copy()如果列表里还有子列表,要小心浅拷贝问题:
a = [[1, 2], [3, 4]]
b = a.copy()
b[0][0] = 99
# a 也会受到影响8. 列表推导式
严格说不是方法,但它是 Python 中处理列表最地道的方式之一。
squares = [x * x for x in range(5)]
evens = [x for x in range(10) if x % 2 == 0]三、元组 tuple
元组是不可变的有序序列。它和列表长得很像,但核心区别是:列表可变,元组不可变。
1. 创建方式
t1 = (1, 2, 3)
t2 = 1, 2, 3
t3 = ()
t4 = (1,) # 单元素元组必须带逗号很多初学者会忘记这个逗号:
(1) # 这只是整数 1
(1,) # 这才是元组2. 为什么需要元组
既然已经有列表了,为什么还要元组?
主要有三个原因:
- 元组表示“这组数据不应该被修改”
- 元组可以作为
dict的 key 或set的元素(前提是内部元素也可哈希) - 元组常用来表示一条固定结构的记录
例如:
point = (3, 5)
student = ("Alice", 20, "Math")3. 常见操作
t = (10, 20, 30)
len(t) # 3
t[0] # 10
t[-1] # 30
t[1:] # (20, 30)
20 in t # True4. 元组的方法为什么很少
因为元组不可变,所以它没有 append()、remove()、sort() 这类修改内容的方法。
内置方法主要只有两个:
count(x)
统计某个元素出现次数。
(1, 2, 2, 3).count(2) # 2index(x[, start[, end]])
返回某个元素第一次出现的位置。
(10, 20, 30).index(20) # 15. 解包
元组最常见的一个用法,是解包:
point = (3, 5)
x, y = point交换变量时也常用它:
a, b = b, a四、字典 dict
字典是 Python 中的键值映射结构。你可以把它理解成“通过 key 快速找到 value”。
1. 创建方式
person = {"name": "Tom", "age": 20}
empty = {}也可以用 dict():
person = dict(name="Tom", age=20)2. 常见基本操作
person = {"name": "Tom", "age": 20}
person["name"] # 'Tom'
person["age"] = 21
"name" in person # True
len(person) # 2字典查的是 key,不是 value。
3. 访问相关方法
get(key[, default])
这是字典里非常值得优先使用的方法。它的好处是:key 不存在时不会报错。
person.get("name") # 'Tom'
person.get("gender") # None
person.get("gender", "N/A") # 'N/A'setdefault(key[, default])
如果 key 存在,返回对应值;如果不存在,就插入一个默认值并返回它。
d = {}
d.setdefault("count", 0) # 0
# d 现在是 {"count": 0}4. 获取所有 key / value / item
keys()
返回所有 key 的视图对象。
values()
返回所有 value 的视图对象。
items()
返回所有 (key, value) 对。
person = {"name": "Tom", "age": 20}
person.keys()
person.values()
person.items()遍历字典时,最常见的是:
for key, value in person.items():
print(key, value)5. 添加、更新、合并
直接赋值
person["city"] = "Beijing"update([other])
用另一个字典或键值对序列更新当前字典。
person.update({"age": 21, "city": "Beijing"})6. 删除方法
pop(key[, default])
删除指定 key,并返回对应值。
person = {"name": "Tom", "age": 20}
person.pop("age") # 20popitem()
删除并返回最后插入的一组键值对。
d = {"a": 1, "b": 2}
d.popitem() # ('b', 2)clear()
清空字典。
7. 复制
copy()
浅拷贝。
8. 从一组 key 创建字典
fromkeys(iterable[, value])
这是一个类方法,不是实例方法。
dict.fromkeys(["a", "b", "c"], 0)
# {'a': 0, 'b': 0, 'c': 0}9. 字典推导式
squares = {x: x * x for x in range(5)}10. dict 使用时的常见注意点
第一,key 必须是可哈希对象。通常字符串、数字、元组可以做 key,但列表不行。
d = {}
d["name"] = "Tom"
# d[[1, 2]] = 3 # TypeError第二,访问不存在的 key 时,d[key] 会报错,而 get() 更温和。
五、集合 set
集合是无序且元素唯一的容器。它最常见的两个用途是:
- 去重
- 做集合运算
1. 创建方式
s = {1, 2, 3}
empty = set() # 不能写成 {}注意:{} 创建的是空字典,不是空集合。
2. 基本特点
集合中的元素必须可哈希,而且不会重复:
{1, 2, 2, 3} # {1, 2, 3}3. 添加与删除
add(x)
添加一个元素。
s = {1, 2}
s.add(3) # {1, 2, 3}update(*others)
把另一个可迭代对象中的元素加入集合。
s = {1, 2}
s.update([2, 3, 4]) # {1, 2, 3, 4}remove(x)
删除元素;如果元素不存在,会报错。
discard(x)
删除元素;如果不存在,不报错。
s = {1, 2, 3}
s.discard(4) # 不会报错pop()
随机删除并返回一个元素。因为集合无序,所以不要假设它弹出的是“第一个”。
clear()
清空集合。
4. 集合运算方法
union(*others) / |
并集。
{1, 2}.union({2, 3}) # {1, 2, 3}
{1, 2} | {2, 3}intersection(*others) / &
交集。
{1, 2} & {2, 3} # {2}difference(*others) / -
差集。
{1, 2, 3} - {2} # {1, 3}symmetric_difference(other) / ^
对称差集,即只在一边出现的元素。
{1, 2} ^ {2, 3} # {1, 3}5. 原地更新版本
上面那些集合运算,还有对应的原地修改版本:
intersection_update()difference_update()symmetric_difference_update()
它们会直接修改原集合。
6. 关系判断
issubset(other) / <=
判断是否为子集。
issuperset(other) / >=
判断是否为超集。
isdisjoint(other)
判断两个集合是否没有交集。
{1, 2}.isdisjoint({3, 4}) # True7. 什么时候该用 set
如果你只是想判断“某个元素在不在”,而且不关心顺序,set 往往比 list 更合适。
例如:
visited = set()
visited.add("node1")
if "node1" in visited:
print("seen")六、五种类型放在一起比较
学完方法之后,更重要的是知道什么时候该选哪一个。
1. 要处理文本,用 str
如果你的数据本质上是一段文字,而不是一组独立元素,就应该优先把它当作字符串处理。
2. 要保存可增删改的有序数据,用 list
列表最灵活,适合绝大多数“动态序列”场景。
3. 要表达不可变记录,用 tuple
如果你希望这组值只是一个固定结构,不想被随意改动,元组很自然。
4. 要做 key-value 映射,用 dict
通过名字找年龄,通过单词找释义,通过配置项找配置值,这些都应该想到字典。
5. 要去重或做集合运算,用 set
只要你发现自己反复写“判断一个元素是否已经出现过”,就应该想一想能不能换成集合。
七、最后总结
如果只从一句话来区分这五种类型,可以这样记:
str:处理文本list:处理可变序列tuple:处理不可变序列dict:处理映射关系set:处理唯一元素集合
而从方法角度看,最关键的分界线是:
str、tuple不可变,所以很多操作会返回新对象list、dict、set可变,所以很多方法会直接修改原对象
初学 Python 时,真正容易混乱的不是“不会用方法”,而是没有建立这种对象模型意识。一旦把“是否可变”“是否有序”“是否允许重复”“是否按 key 访问”这几件事想清楚,后面再看这些方法,就会顺很多。
版权所有
版权归属:Guisong Wu