一、背景
上一篇整理了 Python 中的数字类型和常用运算符。
这一篇继续整理 Python 中最常用的几类容器对象:
- 字符串
- 列表
- 元组
- 集合
- 字典
对应的练习代码主要包括:
19序列简介.py
20序列内建函数.py
21字符串简介.py
22字符串的转移字符.py
23字符串运算.py
24字符串格式化.py
25字符串内建函数.py
26列表简介.py
27列表的方法与函数.py
28列表推导式.py
29元组.py
30集合.py
31字典.py
这些类型是 Python 中非常基础的内容,后面写循环、函数、文件处理、JSON 处理、爬虫解析时都会频繁用到。
二、先理解序列
在 Python 中,字符串、列表、元组都属于序列。
序列的特点是:元素有顺序,可以通过索引访问,也可以通过切片取出一段内容。
例如:
s = "123,456"
print(s[0]) # 1
print(s[0:3]) # 123
print(s[-1]) # 6
print(len(s)) # 7
索引有两种写法:
| 写法 | 说明 |
|---|---|
| 正向索引 | 从 0 开始 |
| 反向索引 | 从 -1 开始,表示最后一个元素 |
需要注意:索引访问超出范围会报错,切片超出范围通常不会报错。
s = "hello"
print(s[10:20]) # ''
# print(s[10]) # IndexError: string index out of range
三、序列常用操作
序列常见操作主要包括成员判断、连接、重复、切片和遍历。
1. 成员判断
s = "123,456"
print("123" in s) # True
print("789" not in s) # True
2. 连接和重复
s1 = "123,456"
s2 = ",789"
print(s1 + s2) # 123,456,789
print(s2 * 3) # ,789,789,789
列表也可以使用 + 连接:
nums1 = [1, 2, 3]
nums2 = [4, 5]
print(nums1 + nums2) # [1, 2, 3, 4, 5]
3. 切片
切片语法如下:
seq[start:end:step]
含义是从 start 开始,到 end 结束,但是不包含 end 位置的元素。
s = "123,456"
print(s[0:2]) # 12
print(s[0:]) # 123,456
print(s[:-1]) # 123,45
print(s[:]) # 123,456
print(s[::2]) # 13,5
4. 遍历
s = "hello"
for item in s:
print(item)
列表、元组也可以使用相同方式遍历。
四、序列常用内置函数
练习代码中整理了一些常见序列函数,实际使用中下面这些最常见。
| 函数 | 作用 | 示例 |
|---|---|---|
len() |
获取长度 | len([1, 2, 3]) |
enumerate() |
同时获取索引和值 | for i, v in enumerate(data) |
max() |
获取最大值 | max([1, 2, 3]) |
min() |
获取最小值 | min([1, 2, 3]) |
sorted() |
排序后返回新列表 | sorted([3, 1, 2]) |
reversed() |
反向迭代 | list(reversed([1, 2, 3])) |
sum() |
求和 | sum([1, 2, 3]) |
zip() |
多个序列按位置组合 | zip(names, ages) |
例如按照年龄排序:
users = [
{"name": "xiaoming", "age": 18},
{"name": "xiaohong", "age": 15},
{"name": "xiaogang", "age": 19},
]
print(sorted(users, key=lambda item: item["age"]))
print(sorted(users, key=lambda item: item["age"], reverse=True))
zip() 常用于把两个列表组合成一组数据:
names = ["xiaoming", "xiaohong", "xiaogang"]
ages = [18, 15, 19]
print(list(zip(names, ages)))
# [('xiaoming', 18), ('xiaohong', 15), ('xiaogang', 19)]
五、字符串
字符串可以使用单引号、双引号或三引号创建。
s1 = "hello"
s2 = 'hello'
s3 = """hello
world"""
单引号和双引号没有本质区别。三引号常用于多行字符串,也可以用于函数或类的文档说明。
1. 字符串不可变
字符串是不可变对象,不能通过索引直接修改某一个字符。
s = "hello"
# s[0] = "H" # TypeError: 'str' object does not support item assignment
s = "Hello"
print(s)
这里不是修改了原来的字符串,而是让变量 s 指向了新的字符串对象。
2. 转义字符和原始字符串
常见转义字符如下:
| 写法 | 含义 |
|---|---|
\n |
换行 |
\t |
制表符 |
\\ |
反斜杠 |
\" |
双引号 |
\' |
单引号 |
示例:
print("hello\npython")
print("name\tage")
如果不希望反斜杠被转义,可以使用原始字符串:
path = r"D:\data\python"
print(path)
3. 字符串格式化
早期代码中经常能看到 % 格式化:
name = "xiaoming"
age = 18
print("name=%s, age=%d" % (name, age))
Python3 中更常用的是 format() 和 f-string。
name = "xiaoming"
age = 18
print("name={}, age={}".format(name, age))
print(f"name={name}, age={age}")
如果需要控制小数位数:
price = 12.3456
print(f"{price:.2f}") # 12.35
4. 字符串常用方法
字符串方法非常多,不需要一次性全部背下来,先掌握常用的。
| 方法 | 作用 |
|---|---|
strip() |
去掉首尾空白字符 |
split() |
按分隔符拆分字符串 |
join() |
使用指定分隔符拼接字符串 |
replace() |
替换字符串内容 |
find() |
查找子串位置,找不到返回 -1 |
startswith() |
判断是否以某内容开头 |
endswith() |
判断是否以某内容结尾 |
lower() |
转小写 |
upper() |
转大写 |
示例:
line = " spark,hive,flink "
line = line.strip()
items = line.split(",")
print(items) # ['spark', 'hive', 'flink']
print("|".join(items)) # spark|hive|flink
print(line.replace(",", ";"))
print(line.startswith("spark"))
print(line.endswith("flink"))
在 Python3 中,字符串默认是 Unicode 字符串。如果需要和字节数据互相转换,使用 encode() 和 decode():
s = "你好"
data = s.encode("utf-8")
print(data)
text = data.decode("utf-8")
print(text)
六、列表
列表使用方括号定义,元素之间用逗号分隔。
nums = [1, 2, 3, 4, 5]
users = ["xiaoming", "xiaohong"]
mixed = [1, 3.14, "hello", True]
列表可以存放不同类型的数据,不过实际开发中,一个列表通常存放同一种业务含义的数据。
1. 列表索引和切片
nums = [1, 2, 3, 4, 5]
print(nums[0]) # 1
print(nums[-1]) # 5
print(nums[0:3]) # [1, 2, 3]
print(nums[-3:-1]) # [3, 4]
2. 列表是可变对象
列表和字符串不同,列表可以直接修改元素。
nums = [1, 2, 3]
nums[0] = 100
nums.append(4)
print(nums) # [100, 2, 3, 4]
也可以通过切片修改列表大小:
nums = [1, 2, 3, 4, 5]
nums[0:2] = []
print(nums) # [3, 4, 5]
3. 列表常用方法
| 方法 | 作用 |
|---|---|
append(obj) |
在末尾追加一个元素 |
extend(seq) |
在末尾追加另一个序列中的多个元素 |
insert(index, obj) |
在指定位置插入元素 |
pop(index) |
删除并返回指定位置元素,默认最后一个 |
remove(obj) |
删除第一个匹配的元素 |
count(obj) |
统计某个元素出现次数 |
index(obj) |
获取某个元素第一次出现的位置 |
reverse() |
原地反转列表 |
sort() |
原地排序列表 |
clear() |
清空列表 |
copy() |
浅拷贝列表 |
示例:
nums = [1, 2, 3]
nums.append(4)
nums.extend([5, 6])
nums.insert(0, 100)
print(nums) # [100, 1, 2, 3, 4, 5, 6]
last = nums.pop()
print(last) # 6
nums.remove(100)
print(nums) # [1, 2, 3, 4, 5]
排序示例:
nums = [1, 3, 4, 2]
nums.sort()
print(nums) # [1, 2, 3, 4]
nums.sort(reverse=True)
print(nums) # [4, 3, 2, 1]
需要注意:sort() 会修改原列表,sorted() 会返回一个新列表。
nums = [3, 1, 2]
new_nums = sorted(nums)
print(nums) # [3, 1, 2]
print(new_nums) # [1, 2, 3]
4. 不要把变量命名为 list
练习代码中有 list = [1, 2, 3] 这种写法。学习阶段能运行,但是不建议这样写。
因为 list 是 Python 内置类型名称,一旦被变量覆盖,后面再调用 list() 就可能出现问题。
建议写成:
nums = [1, 2, 3]
names = ["xiaoming", "xiaohong"]
5. 列表推导式
列表推导式用于快速生成列表。
nums = [2 * x + 1 for x in range(10) if x != 3]
print(nums)
# [1, 3, 5, 9, 11, 13, 15, 17, 19]
也可以写多层循环:
items = [(x, y) for x in [1, 2, 3] for y in ["a", "b"]]
print(items)
# [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')]
列表推导式适合简单转换。如果逻辑太复杂,直接写 for 循环更清楚。
七、元组
元组使用圆括号定义。
t = (1, 2, 3)
print(t[0]) # 1
print(t[-1]) # 3
元组也是序列,可以索引和切片,但是元组本身不可变。
t = (1, 2, 3)
# t[0] = 100 # TypeError: 'tuple' object does not support item assignment
1. 单个元素的元组
定义只有一个元素的元组时,逗号不能省略。
t1 = (1)
t2 = (1,)
print(type(t1)) # <class 'int'>
print(type(t2)) # <class 'tuple'>
2. 元组中可以包含可变对象
元组不可变,指的是元组中保存的引用不能变。
如果元组中保存的是列表,列表本身仍然可以被修改。
t = ([1, 2, 3], [4, 5, 6])
t[1][0] = "hello"
print(t)
# ([1, 2, 3], ['hello', 5, 6])
3. 元组和列表的区别
| 类型 | 是否有序 | 是否可变 | 常见用途 |
|---|---|---|---|
| 列表 | 有序 | 可变 | 保存一组需要增删改的数据 |
| 元组 | 有序 | 不可变 | 保存结构固定的数据 |
比如一个坐标点可以用元组表示:
point = (10, 20)
而一组用户名称更适合用列表:
names = ["xiaoming", "xiaohong", "xiaogang"]
八、集合
集合使用大括号或 set() 创建。
s1 = {1, 2, 3, 4}
s2 = set("hello")
print(s1)
print(s2)
集合有两个重要特点:
- 元素不能重复
- 元素没有固定顺序
例如:
s = {1, 2, 3, 4, 4, 3, 2, 1}
print(s)
# {1, 2, 3, 4}
1. 空集合
空集合不能写成 {},因为 {} 表示空字典。
s = set()
print(type(s)) # <class 'set'>
print(type({})) # <class 'dict'>
2. 集合常用方法
| 方法 | 作用 |
|---|---|
add() |
添加一个元素 |
update() |
批量添加元素 |
remove() |
删除指定元素,元素不存在时报错 |
discard() |
删除指定元素,元素不存在不报错 |
pop() |
随机删除并返回一个元素 |
clear() |
清空集合 |
示例:
s = {1, 2, 3}
s.add(4)
s.update([5, 6])
s.discard(100)
print(s)
如果不确定元素是否存在,优先使用 discard()。
3. 集合运算
集合很适合做去重和关系运算。
sa = {1, 2, 3, 4}
sb = {3, 4, 5, 6}
print(sa - sb) # {1, 2}
print(sa & sb) # {3, 4}
print(sa | sb) # {1, 2, 3, 4, 5, 6}
print(sa ^ sb) # {1, 2, 5, 6}
对应含义如下:
| 运算 | 含义 |
|---|---|
a - b |
在 a 中,但是不在 b 中 |
a & b |
同时在 a 和 b 中 |
| `a | b` |
a ^ b |
在 a 或 b 中,但是不同时在两者中 |
一个常见场景是列表去重:
names = ["a", "b", "a", "c"]
print(set(names))
# {'a', 'b', 'c'}
如果要保留原始顺序,可以使用字典:
names = ["a", "b", "a", "c"]
print(list(dict.fromkeys(names)))
# ['a', 'b', 'c']
九、字典
字典用于保存键值对。
user = {
"name": "xiaoming",
"age": 18,
}
字典的特点:
- 通过
key查找value key不能重复value可以重复
1. 创建字典
d1 = {"k1": "v1", "k2": "v2"}
d2 = dict([("k1", "v1"), ("k2", "v2")])
print(d1)
print(d2)
2. 访问和修改元素
user = {"name": "xiaoming", "age": 18}
print(user["name"])
print(user.get("age"))
user["city"] = "beijing"
user["age"] = 20
print(user)
[] 和 get() 都可以取值,但是行为不同。
user = {"name": "xiaoming"}
# print(user["age"]) # KeyError: 'age'
print(user.get("age")) # None
print(user.get("age", 0)) # 0
如果 key 可能不存在,使用 get() 更稳。
3. 字典常用方法
| 方法 | 作用 |
|---|---|
get(key, default) |
获取值,不存在时返回默认值 |
keys() |
获取所有 key |
values() |
获取所有 value |
items() |
获取所有 key/value |
pop(key) |
删除并返回指定 key 的 value |
update(dict) |
合并或更新字典 |
clear() |
清空字典 |
示例:
user = {"name": "xiaoming", "age": 18}
print(user.keys())
print(user.values())
print(user.items())
user.update({"age": 20, "city": "beijing"})
print(user)
age = user.pop("age")
print(age)
print(user)
4. 遍历字典
遍历 key:
user = {"name": "xiaoming", "age": 18}
for key in user.keys():
print(key, user.get(key))
同时遍历 key 和 value:
for key, value in user.items():
print(key, value)
遍历 value:
for value in user.values():
print(value)
实际开发中,items() 用得最多。
5. 字典推导式
字典推导式可以快速生成字典。
values = ["xiaoming", "xiaohong", "xiaogang"]
users = {index: value for index, value in enumerate(values)}
print(users)
# {0: 'xiaoming', 1: 'xiaohong', 2: 'xiaogang'}
也可以对已有字典做过滤:
scores = {
"xiaoming": 90,
"xiaohong": 75,
"xiaogang": 88,
}
passed = {name: score for name, score in scores.items() if score >= 80}
print(passed)
# {'xiaoming': 90, 'xiaogang': 88}
十、几种容器类型对比
| 类型 | 写法 | 是否有序 | 是否可变 | 是否允许重复 | 常见用途 |
|---|---|---|---|---|---|
| 字符串 | "abc" |
有序 | 不可变 | 允许 | 文本处理 |
| 列表 | [1, 2, 3] |
有序 | 可变 | 允许 | 保存一组可变数据 |
| 元组 | (1, 2, 3) |
有序 | 不可变 | 允许 | 保存结构固定的数据 |
| 集合 | {1, 2, 3} |
无固定顺序 | 可变 | 不允许 | 去重、集合运算 |
| 字典 | {"k": "v"} |
有序 | 可变 | key 不允许重复 | 保存键值对 |
这里的字典有序,是指 Python 3.7 之后语言层面保证字典会保留插入顺序。
十一、总结
这一篇主要整理了 Python 中最常用的几类容器对象。
需要重点记住:
- 字符串、列表、元组都属于序列,都支持索引、切片和遍历
- 字符串和元组不可变,列表可变
- 集合适合去重和集合运算
- 字典适合保存键值对,实际开发中非常常用
list、dict、str、set这些内置名称不要拿来当变量名
这些内容本身不难,但是会在后面的循环、函数、文件、JSON、爬虫解析中反复出现。