Python 数据容器
·
一、为什么需要数据容器
- 养鸡场问题:一个养鸡场有6只鸡,他们的体重分别是3kg,5kg,1kg,3.4kg,2kg,50kg。请问这六只鸡的总体重是多少?平均体重是多少?
hen1 = 3 hen2 = 5 hen3 = 1 hen4 = 3.4 hen5 = 2 hen6 = 50 # 计算总的体重 total_weight = hen1 + hen2 + hen3 + hen4 + hen5 + hen6 # 计算平均体重 avg_weight = total_weight / 6 print(f"总体重:{total_weight} 平均体重:{avg_weight}") - Python 和 Java 在变量机制上的核心差异:
- Python定义变量时,无需显式声明变量的数据类型,变量的类型由赋值符号 = 右侧的数据对象动态决定;而 Java 作为静态类型语言,声明变量时必须指定数据类型,该变量会被分配固定大小的内存空间,且只能存储对应类型的数据(除非进行显式类型转换)
- 从底层逻辑来看,Python 中的变量更像是指向数据对象的引用(别名)——变量本身不存储数据,仅记录数据对象在内存中的地址。当给变量重新赋值时,本质上是让这个引用指向了新的数据对象(地址改变);而 Java 变量(基础类型)直接存储数据值,内存空间大小由类型固定,赋值时是修改内存中的值
- Python 中的 + 运算符(加法)的行为是由操作数的数据类型来决定:
- 当操作数均为数字类型(整数 int、浮点数 float、复数 complex等等)时,+ 执行数学意义上的加法运算
- 当操作数均为字符串类型(str)时,+ 执行字符串拼接操作
- 若操作数是字符串与数字(或其他不兼容类型)混合相加,会直接抛出 TypeError(类型错误),因为 Python 不支持不同类型的隐式转换后相加
- 除了数字和字符串外,Python 中还有不少内置类型也实现了合法的 + 运算,例如列表(list)、元组(tuple)等序列类型,+ 会执行同类型序列的拼接(如 [1,2] + [3,4] 得到 [1,2,3,4])
- 本质上,+ 运算符的合法性取决于类型是否实现了__add__魔法方法:只要类型自定义了该方法,就能支持 + 运算(比如自定义类也可以重写__add__实现自定义加法逻辑);未实现则会抛出类型错误
- round 函数:
- 参考文档:内置函数 — Python 3.14.3 文档
- 基本用法:
- round(number,ndigits = None)就是四舍五入
- 给一个数字 number,让它舍入到小数点后 ndigits 位
- 如果不写 ndigits 或者写 None,就返回最接近的整数
print(round(3.14159)) # 不写ndigits → 3 print(round(3.14159, 2)) # 保留2位小数 → 3.14
- 特殊规则:
- round() 遇到 0.5、1.5 这类“正中间”的数时,不进1,而是舍入到最近的偶数
- 举例:
print(round(1.5)) # 结果是2(最近的偶数) print(round(2.5)) # 结果是2(最近的偶数)
- ndigits 不只是正数、0,还可以是负数:
- ndigits = -1,舍入到十位
- ndigits = -2,舍入到百位

- 小数的四舍五入核心是:看要保留的小数位的后一位数字,若 ≥5 则向前进1,若 <5则直接舍去
- 整数的四舍五入逻辑是:(1)凑整到十位时,看个位数字,≥5 则十位进1(个位补0),<5则直接舍去个位(个位补0)(2)凑整到百位时,看十位数字,≥5 则百位进1(十位、个位补0),<5则直接舍去十位和个位(补0)(3)以此类推(凑整到千位看百位,凑整到万位看千位)
- 浮点数的坑:
- 有些十进制小数,在计算机里其实是用二进制近似表示的,所以 round 的结果可能和直觉不一样
print(round(2.675,2)) # 输出 2.67,而不是以为的2.68 - 这不是bug,是因为 2.675 这个数在计算机里,真实存储值比 2.675 稍微小一点,所以舍入时就变成了 2.67
- 有些十进制小数,在计算机里其实是用二进制近似表示的,所以 round 的结果可能和直觉不一样
- 自定义对象也能用 round
- 只要一个对象实现了__round__方法,round()就能对它生效,比如你自己编写的类
- 代码举例:
class MyNum: def __init__(self, val): self.val = val def __round__(self,ndigits = None): return round(self.val,ndigits) n = MyNum(3.14159) print(n.val) # 3.14159 print(round(n,2)) # 3.14 - round() 函数的核心作用对象是数字类型(整数、浮点数),但是它并非只能处理数字——对于自定义类创建的对象,只要在类中实现了__round__魔法方法,就可以对该对象调用 round() 函数。此时该函数的执行逻辑,本质上是除法该对象调用自身的__round__方法,执行方法内部自定义的逻辑
二、什么是数据容器
(1)基本介绍
- 数据容器(比如列表、元组、字典、集合等等)是 Python 中的一类数据类型,其核心特征是可以集中存放多个数据项(每个数据项称为“元素”)
- 核心基础容器(列表、元组、字典)支持不同类型元素,部分特殊容器仅支持同类型元素
- 数据容器简单示意图:

(2)分类
- 列表(list)
- 元组(tuple)
- 字符串(str)
- 集合(set)
- 字典(dict)
三、列表(List)
(1)基本介绍
- 列表可以存放多个不同类型数据
- 列表也是一种数据类型
(2)列表的定义
- 创建一个列表,只要用逗号分隔不同的数据项使用方括号括起来即可,示例如下:
list1 = [100,200,300,400,500] list2 = ['red','green','blue','yellow','white','black'] - 说明:

- 代码说明:
list1 = [100,200,300,400,500] # 输出列表数据 print(list1) print(type(list1))
(3)列表的使用
- 列表的使用语法:
列表名[索引] - 举例说明:
# 列表的使用语法 list2 = ['red','green','blue','yellow','white','black'] # 列出所有的数据 print(list2) # 访问/获取第三个数据/元素 print("第三个元素是:",list2[2]) - 注意:索引是从0开始计算的
(4)列表的遍历
- 列表的遍历:简单的说,就是将列表的每个元素依次取出,进行处理,就是遍历/迭代
- 实例:使用while循环,对列表进行遍历输出
list_color = ['red','green','blue','yellow','white','black'] # 先定义变量index = 0,表示从第一个元素开始取出 index = 0 while index < len(list_color): print(f"第{index + 1}个元素的是:{list_color[index]}") index += 1 - 实例:使用for循环,对列表进行遍历输出
list_color = ['red','green','blue','yellow','white','black'] # 因为for循环就是直接从列表中依次取出,所以直接操作即可 index = 0 for element in list_color: print(f"第{index + 1}个元素的是:{element}") index += 1
(5)列表解决养鸡场问题
# 使用列表解决养鸡场问题
hens = [3,5,1,3.4,2,50]
# 计算总的体重
total_weight = 0.0
# 遍历hens
for ele in hens:
# 累加
total_weight += ele
print(f"总体重:{total_weight} 平均体重:{round((total_weight/len(hens)),2)}")
(6)注意事项和使用细节
- 如果我们需要一个空列表,可以通过[],或者list()方式来定义
list1 = [] list2 = list() print(list1,type(list1)) print(list2,type(list2)) - 参考文档:内置类型 — Python 3.14.3 文档
- Python中的列表(list)是有序的数据容器,其核心特征包括:
- 可容纳多个元素,且元素支持不同数据类型(如整数、字符串、浮点数等等)
- 允许存放重复元素,即使元素值相同,也可以通过唯一的索引(下标)精准定位和区分
- 列表的“有序性”本质由索引决定——元素的存储顺序固定,且每个元素对应唯一的索引(从0开始递增),通过索引可以按照顺序访问或者操作元素
list3 = [100,"jack",4.5,True] print(list3) # 嵌套列表 list4 = [100,"tom",["天龙八部","笑傲江湖",300]] print("list4 =",list4)
- 列表的索引/下标是从0开始的
- 列表索引必须在指定范围内使用,否则报错
# 比如list5的有效下标位0-2 list5 = [1,2.1,"tom"] # 索引越界 print(list5[3]) - 索引也可以从尾部开始,最后一个元素的索引为-1,往前一位为-2,以此类推
list1 = [1,2.1,"tom"] print(list1[-1]) print(list1[-2]) # 依然不能索引越界 print(list1[-4]) - 通过 列表[索引] = 新值 对数据进行更新,使用 列表.append(值)的方法来添加元素,使用 del 语句来删除列表的元素,注意不能超出有效索引范围
list_a = ["天龙八部","笑傲江湖"] print("list_a:",list_a) # list_a: ['天龙八部', '笑傲江湖'] list_a[0] = "雪山飞狐" print("list_a:",list_a) # list_a: ['雪山飞狐', '笑傲江湖'] list_a.append("倚天屠龙") print("list_a:",list_a) # list_a: ['雪山飞狐', '笑傲江湖', '倚天屠龙'] del list_a[0] print("list_a:",list_a) # list_a: ['笑傲江湖', '倚天屠龙'] - 列表在赋值时的特点:
list1 = [1, 2.1, "tom"] list2 = list1 list2[0] = 500 print("list2:", list2) print("list1:", list1)
- 列表在函数传参时的特点:
def f1(l): l[0] = 100 print("l的id:", id(l)) list10 = [1, 2.1, 200] print("list10的id:", id(list10)) f1(list10) print("list10:", list10)
- 列表是可变序列:列表变量本身存储的是列表对象在内存中的地址(引用),而列表内部的每个元素位置,存储的并非数据内容本身,而是对应数据对象的引用(即该数据在内存中的地址)
- 当修改列表中的某个元素时(比如 lst[0] = 10),本质是把列表该位置的引用指向了新的数据对象(10的内存地址),列表对象本身在内存中的地址(即列表变量指向的地址)完全不变
list1 = [1,2.1,"tom"] print(f"list:{list1} 地址:{id(list1)} {id(list1[2])} {list1[2]}") list1[2] ="jack" print(f"list:{list1} 地址:{id(list1)} {id(list1[2])} {list1[2]}") - 当对列表做增删操作时(比如 lst.append(20)、del lst[1]),列表会直接在原有内存空间里调整元素的引用集合,列表对象本身的内存地址依然不变
- 正因为列表对象可以在不改变自身内存地址的前提下,修改内部的元素引用、调整元素数量,所以列表被称为“可变序列”
- 当修改列表中的某个元素时(比如 lst[0] = 10),本质是把列表该位置的引用指向了新的数据对象(10的内存地址),列表对象本身在内存中的地址(即列表变量指向的地址)完全不变
(7)列表常用操作
| 序号 | 函数 |
|---|---|
| 1 | len(list):列表元素个数 |
| 2 | max(list):返回列表元素最大值 |
| 3 | min(list):返回列表元素最小值 |
| 4 | list(seq):将元组转换为列表 |
| 5 | list.append(obj):在列表末尾添加新的对象 |
| 6 | list.count(obj):统计某个元素在列表中出现的次数 |
| 7 | list.extend(seq):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表) |
| 8 | list.index(obj):从列表中找出某个值第一个匹配项的索引位置 |
| 9 | list.insert(index, obj):将对象插入列表 |
| 10 | list.pop([index =-1]):移除列表中的一个元素(默认最后一个元素),并返回该元素的值 |
| 11 | list.remove(obj):移除列表中某个值的第一个匹配项 |
| 12 | list.reverse():反向列表中元素 |
| 13 | list.sort(key = None, reverse = False):对原列表进行排序 |
| 14 | list.clear():清空列表 |
| 15 | list.copy():复制列表 |
# 演示列表常用操作
list_a = [100, 200, 300, 400, 600]
print("list_a 列表元素个数:", len(list_a))
print("list_a 列表最大元素:", max(list_a))
print("list_a 列表最小元素:", min(list_a))
# list.append(obj):在列表末尾添加新的对象
# 请在list_a列表后,添加900
list_a.append(900)
list_a.append(100)
print("list_a:",list_a)
# list.count(obj):统计某个元素在列表中出现的次数
print(f"100出现的次数是:{list_a.count(100)}")
# list.extend(seq):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
list_b = [1,2,3]
# 将list_b追加到list_a
list_a.extend(list_b)
print("list_a:",list_a)
# list.index(obj):从列表中找出某个值第一个匹配项的索引位置
# 如果找不到,会报错:ValueError
# print("1000第1次出现在序列的索引是:", list_a.index(1000)) # ValueError: 1000 is not in list
print(f"300第1次出现在序列的索引是:{list_a.index(300)}")
# list.reverse():反向列表中元素
list_a.reverse()
print("list_a:",list_a)
# list.insert(index, obj):将对象插入列表
# 请实现把666插入到index为1的位置
list_a.insert(1,666)
print("list_a:",list_a)
# list.pop([index=-1]):移除列表中的一个元素(默认最后一个元素),并返回该元素的值
print(list_a.pop())
print("list_a:",list_a)
# list.remove(obj):移除列表中某个值的第一个匹配项
list_a.remove(666)
print("list_a:",list_a)
# list.sort(key=None, reverse=False):对原列表进行排序
list_a.sort()
print("list_a:",list_a)
# list.copy():复制列表
list_c = list_a.copy()
print("list_c:",list_c)
# list.clear():清空列表
list_a.clear()
print(list_a)
(8)列表生成式
- 列表生成式就就是“生成列表的公式”
- 基本语法:
[列表元素的表达式 for 自定义变量 in 可迭代对象] [ele * 2 for ele in range(1,5)] =得到列表==>[2,4,6,8] - 再举一个案例,要求生成一个列表,内容为[1,4,9,16,25,36,49,64,81,100]
list1 = [ele * ele for ele in range(1,11)] print("list1 =",list1)
四、元组(tuple)
(1)基本介绍
- 元组(tuple)可以存放多个不同类型数据,元组是不可变序列
- 元组变量存储的是元组对象在内存中的地址(引用),元组内部的每个元素位置,存储的并非数据内容本身,而是对应数据对象的引用(即该数据在内存中的地址)
- 元组的“不可变”,本质是指元组对象一旦创建,其内部元素的引用(地址)与元素数量就无法被修改(没有append()、insert()这样的方法,也不能重新赋值)
- 无法直接修改元组中某个位置的元素(比如 tuple[0] = 10 会报错),因为这等同于要改变元组该位置绑定的引用
- 无法对元组做增删元素的操作(比如tuple.append(20)、del tuple[1]均无此方法且会报错),因为这会改变元组的元素数量和引用集合
- 特别注意:如果元组中的元素是可变对象(比如列表),虽然元组对这个列表的引用无法改变,但列表对象自身的内容可以修改(这并不违背元组 “不可变” 的定义)
- 元组也是一种数据类型
(2)元组的定义
- 创建一个元组,只要把逗号分隔的不同的数据项,使用圆括号括起来即可,示例如下:
tuple_a = (100,200,300,400,500) tuple_b = ('red','green','blue','yellow','white','black') - 案例演示:
tuple_a = (100,200,300,400,500) # 输出元组数据 print(f"元组的内容是{tuple_a} 类型是:{type(tuple_a)}")
(3)元组的使用
- 元组使用语法:
元组名[索引] - 举例说明:
tuple_c = ('red','green','blue','yellow','white','black') # 比如,要使用元组的第三个值"blue",则通过tuple_c[2]就可以访问到 # 提示:索引是从0开始计算的 - 代码演示,访问/获取第三个数据/元素:
tuple_c = ('red','green','blue','yellow','white','black') print(tuple_c[2])
(4)元组的遍历
- 什么是元组的遍历:简单的说,就是将元组的每个元素依次取出,进行处理的操作,就是遍历/迭代
- 实例:使用while循环,对列表进行遍历输出
tuple_color = ('red','green','blue','yellow','white','black') index = 0 while index < len(tuple_color): print(f"元素是:{tuple_color[index]}") index += 1 - 实例:使用for循环,对列表进行遍历输出
tuple_color = ('red','green','blue','yellow','white','black') for ele in tuple_color: print(f"元素是:{ele}")
(5)注意事项和使用细节
- 如果我们需要一个空元组,可以通过(),或者tuple()方式来定义
tuple_a = () tuple_b = tuple() print(f"tuple_a 的内容是{tuple_a} 类型是{type(tuple_a)}") print(f"tuple_a 的内容是{tuple_a} 类型是{type(tuple_b)}") - 元组的元素可以有多个,而且数据类型没有限制(甚至可以嵌套元组),允许有重复元素,并且是有序的
tuple_c = (100,'jack',4.5,True,'jack') print(tuple_c) # (100, 'jack', 4.5, True, 'jack') # 嵌套元组 tuple_d = (100,"tom",("天龙八部","笑傲江湖",300)) print("tuple_d =",tuple_d) # tuple_d = (100, 'tom', ('天龙八部', '笑傲江湖', 300)) - 元组的索引/下标是从0开始的
- 元组索引必须在指定范围内使用,否则报错,
- 元组是不可变序列
- 可以修改元组内list的内容(包括修改、增加、删除等等)
tuple_f = (1,2.1,'bob',["jack","tom","mary"]) # 访问元组中list及其元素 print(tuple_f[3]) print(tuple_f[3][0]) # 修改 tuple_f[3][0] = "john" print(f"tuple_f 内容是 {tuple_f}") # 删除 del tuple_f[3][0] print(f"tuple_f 内容是 {tuple_f}") # 增加 tuple_f[3].append("smith") print(f"tuple_f 内容是 {tuple_f}") - 索引也可以从尾部开始,最后一个元素的索引为-1,往前一位为-2,以此类推
tuple_g = (1,2.1,'bob',["jack","tom","mary"]) print(tuple_g[-2]) - 定义只有一个元素的元组,需要带上逗号,否则就不是元组类型
tuple_h = (100,) print(f"tuple_h的类型是{type(tuple_h)}") - 既然有了列表,python设计者为什么还提供元组这样的数据类型呢?
- 在项目中,尤其是多线程环境中,有经验的程序员会考虑使用不变对象(一方面是因为对象状态不能修改,所以可以避免由此引起的不必要的程序错误;另一方面一个不变对象自动就是线程安全的,这样就可以省掉处理同步化的开销。可以方便地被共享访问)。所以,如果不需要对元素进行添加、删除、修改的情况下,可以考虑使用元组
- 元组在创建时间和占用的空间上面都优于列表
- 元组能够对不需要修改的数据写保护
(6)元组常用操作
| 序号 | 操作 |
|---|---|
| 1 | len(tuple):元组元素个数 |
| 2 | max(tuple):返回元组元素最大值 |
| 3 | min(tuple):返回元组元素最小值 |
| 4 | tuple.count(obj):统计某个元素在元组中出现的次数 |
| 5 | tuple.index(obj):从元组中找出某个值第一个匹配项的索引位置 |
tuple_a = (100,200,300,400,600,200)
print(f"tuple_a 元组元素个数:{len(tuple_a)}")
print(f"tuple_a 元组最大元素:{max(tuple_a)}")
print(f"tuple_a 元组最小元素:{min(tuple_a)}")
# tuple.count(obj):统计某个元素在列表中出现的次数
print(f"100出现的次数是:{tuple_a.count(100)}")
print(f"200出现的次数是:{tuple_a.count(200)}")
# tuple.index(obj):从列表中找出某个值第一个匹配项的索引位置
# 如果找不到就会报错
print(f"200第1次出现在元组的索引是:{tuple_a.index(200)}")
(7)课堂练习
# 定义一个元组:("大话西游", "周星驰", 80, ["周星驰", "小甜甜"])
# 信息为:(片名, 导演, 票价, 演员列表)
tuple_movie = ("大话西游","周星驰",80,["周星驰","小甜甜"])
# 1)查询票价对应的索引
print(f"票价对应索引:{tuple_movie.index(80)}")
# 2)遍历所有的演员
for ele in tuple_movie[3]:
print(f"演员的名字:{ele}")
# 3)删除'小甜甜',增加演员'牛魔王'、'猪八戒'
del tuple_movie[3][1]
tuple_movie[3].extend(['牛魔王','猪八戒'])
print(tuple_movie)
五、字符串(str)
(1)基本介绍
- 在python中处理文本数据是使用str对象,也称为字符串。字符串是由Unicode码位构成的不可变序列
- Unicode码是一种字符编码
- ord()返回单个字符对应的Unicode编码值
- 字符串字面值有三种写法
- 单引号:'允许包含有"双"引号'
- 双引号:"允许嵌入'单'引号"
- 三重引号:'''三重单引号''',"""三重双引号""",使用三重引号的字符串可以跨越多行——其中所有的空白字符都将包含在该字符串的字面值中
- 字符串是字符的容器,一个字符串可以存放多个字符

(2)字符串支持索引
- 使用语法:
字符串名[索引] - 注意:索引是从0开始计算的,取出的单个字符,类型仍然是字符串
- 代码演示:
str_a = "red-green" print("str_a的第三个值/字符是:", str_a[2], type(str_a[2]))
(3)字符串的遍历
- 什么是字符串的遍历:简单的说,就是将字符串的每个元素依次取出,进行处理的操作,就是遍历/迭代
- 实例:使用while/for循环,对列表进行遍历输出
# 使用while和for遍历字符串 str_b = "hi_tom" # while循环遍历 index = 0 while index < len(str_b): print(str_b[index]) # 循环控制遍历增1 index += 1 print("=========================") # print("=" * 25) # for循环遍历 for ele in str_b: print(ele)
(4)注意事项和使用细节
- 字符串索引必须在指定范围内使用,否则报错。索引也可以从尾部开始,最后一个元素的索引为-1,往前一位为-2,以此类推
- 字符串是不可变序列,不能修改
str_b = "hi-tom" # 通过索引可以访问指定元素 print(str_b[3]) # 不能修改元素 # str_b[3] = "李" - 在Python中,字符串长度没有固定的限制,取决于计算机内存的大小
(5)字符串常用操作
| 序列 | 操作 |
|---|---|
| 1 | len(str):字符串的长度,也就是包含了多少个字符 |
| 2 | str.replace(old,new[,count]):返回字符串的副本,其中出现的所有字符串old都将被替换为new。如果给出了可选参数count,则只替换前count次出现 |
| 3 | str.split(seq = None,maxsplit = -1):返回一个由字符串内单词组成的列表,使用seq作为分隔字符串。如果给出了maxsplit,则最多进行maxsplit次拆分(因此,列表最多会有maxsplit+1个元素)。如果maxsplit未指定或为-1,则不限制拆分次数(进行所有可能的拆分) |
| 4 | str.count(sub):统计指定字符串在字符串中出现的次数 |
| 5 | ste.index(sub):从字符串中找出指定字符串第一个匹配项的索引位置 |
| 6 | str.strip([chars]):返回原字符串的副本,移除其中的前导和末尾字符。chars为指定要移除字符的字符串 |
| 7 | str.lower():返回原字符串小写的副本 |
| 8 | str.upper():返回原字符串大写的副本 |
# 演示字符串常用操作
str_names = "jack tom mary hsp nono tom"
# len(str):字符串的长度,也就是包含多少个字符
print(len(str_names))
# str.replace(old, new[, count]):返回字符串的副本,其中出现的所有子字符串old都将被替换为new。如果给出了可选参数count,则只替换前count次出现。
# 说明:返回字符串的副本:表示原来的字符串不变,而是返回一个新的字符串。
# 需求:将"jack"替换成"杰克",只替换一个。
str_names_new = str_names.replace("jack","杰克",1)
print(str_names_new)
# str.split(sep=None,maxsplit=-1):返回一个由字符串内单词组成的列表,使用seq作为分隔字符串。如果给出了maxsplit,
# 则最多进行maxsplit次拆分(因此,列表最多会有maxsplit+1个元素)。如果maxsplit
# 未指定或为-1,则不限制拆分次数(进行所有可能的拆分)
# 需求:对str_names按照" "进行分割
str_names_split = str_names.split(" ")
print(f"str_names_split 内容是 {str_names_split} 类型是:{type(str_names_split)}")
print(f"str_names 内容是:{str_names}")
# str.count(sub):统计指定字符串在字符串中出现的次数
# 统计tom在字符串中出现了几次
print("tom在字符串出现的次数:",str_names.count("tom"))
# str.index(sub):从字符串中找出指定字符串第一个匹配项的索引位置
print(f"tom出现的索引是:{str_names.index("tom")}")
# str.strip([chars]):返回原字符串的副本,移除其中的前导和末尾字符。chars 为指定要移除字符的字符串
# 说明:这个方法通常用于除去前后的空格,或者去掉制定的某些字符
# 需求,去掉字符的前后的空格
str_names_strip = str_names.strip(" ")
print("str_names_strip:",str_names_strip)
print("123jack321".strip("12")) # 3jack3
# str.lower():返回原字符串小写的副本
# 需求:将字符串字母全部改成小写
str_names = "hspHsp"
str_names_lower = str_names.lower()
print("str_names_lower:",str_names_lower)
print("str_names:",str_names)
# str.upper():返回原字符串大写的副本
str_names_upper = str_names.upper()
print("str_names_upper:",str_names_upper)
print("str_names:",str_names)
(6)字符串比较
- 运算符:>,>=,<,<=,==,!=
- 比较规则:首先比较两个字符串中的第一个字符,如果相等则继续比较下一个字符,依次比较下去,直到两个字符串中的字符不相等时,其比较结果就是两个字符串的比较结果,两个字符串中的所有后续字符将不再被比较
- 比较原理:两个字符进行比较时,比较的是其ordinal value(原始值/码值),调用内置函数ord可以得到指定字符的ordinal value。与内置函数ord对应的是内置函数chr,调用内置函数chr时指定ordinal value可以得到其对应的字符
(7)课堂练习
"""
定义一个字符串,str_names="tom jack mary nono smith hsp"
统计一共有多少个人名;
如果有"hsp"则替换成"老韩";
如果人名是英文,则把首字母改为大写
str.capitalize():字符串首字符改为大写
"""
str_names = "tom jack mary nono smith hsp"
# 统计一共有多少个人名
str_names_split = str_names.split(" ")
print(len(str_names_split))
# 如果有"hsp"则替换成"老韩"
str_names_new = str_names.replace("hsp","老韩")
print(str_names_new)
# 如果人名是英文,则把首字母改为大写
str_names_upper = ""
for ele in str_names_split:
if ele.isalpha():
str_names_upper += ele.capitalize() + " "
# 去掉两边的" "
str_names_upper = str_names_upper.strip(" ")
print(str_names_upper)
六、切片
(1)基本介绍
- 什么是切片:从一个序列中,取出一个子序列,在实际开发中,程序员经常对序列进行切片操作
- 什么是序列:序列是指,内容连续、有序,可使用索引的一类数据容器
- 我们前面学习过的,列表(list)、元组(tuple)、字符串均可视为序列
(2)基本语法
- 基本语法:
序列[起始索引:结束索引:步长]- 表示从序列中,从指定的起始索引开始,按照指定的步长,依次取出元素,到指定结束索引为止,截取到一个新的序列
- 切片操作是前闭后开,也就是[起始索引:结束索引),即截取的子序列,包括起始索引,但是不包括结束索引的部分
- 步长表示,依次取出元素的间隔
- 步长为1:一个一个的取出元素
- 步长为2:每次跳过一个元素取出
- 步长为N:每次跳过N-1个元素取出
- 举例说明:
# 对字符串进行切片 str1 = "hello,world" # 需求:截取"hello" str_slice = str1[0:5:1] print("str_slice:",str_slice) # 对列表进行切片 list_a = ["jack", "tom", 'yoyo', "nono", "hsp"] # 需求:截取["tom","nono] print(list_a[1:4:2]) # 对元组进行切片 tuple_a = (100, 200, 300, 400, 500, 600) # 需求:截取(200,300,400,500) print(tuple_a[1:5:1])
(3)注意事项和使用细节
- 起始索引如果不写,默认为0,结束索引如果不写,默认为截取到结尾,步长如果不写,默认为1
str_a = "hello,韩顺平教育" str_slice01 = str_a[:5:1] print("str_slice01", str_slice01) # hello str_slice02 = str_a[1::1] print("str_slice02", str_slice02) # ello,韩顺平教育 str_slice03 = str_a[::1] print("str_slice03", str_slice03) # hello,韩顺平教育 str_slice04 = str_a[2:5:] print("str_slice04", str_slice04) # llo - 步长为负数,表示反向取,同时注意起始索引和结束索引也要反向标记
str_b = "123456" str_slice05 = str_b[-1::-1] print("str_slice05", str_slice05) # 654321 str_slice06 = str_b[-1:-6:-1] print("str_slice06", str_slice06) # 65432 - 切片操作并不会影响原序列,而是返回了一个序列
str1 = "ABCD" str_slice07 = str1[1:3:1] print(f"str1->{str1} str_slice07->{str_slice07}")
(4)课堂练习
# 定义列表list_name = ["Jack","Lisa","Hsp","Paul","Smith","Kobe"]
list_name = ["Jack","Lisa","Hsp","Paul","Smith","Kobe"]
# 取出前三个名字
print(list_name[0:3:1])
# 取出后三个名字,并且保证原来顺序
print(list_name[3:6:1])
七、集合(set)
(1)基本介绍
- Python支持集合这种数据类型,集合是由不重复元素组成的无序容器
- 不重复元素:简单的说就是集合中不会有相同的元素
- 无序:集合中元素取出的顺序,和你定义时元素顺序并不能保证一致
- 集合对象支持合集、交集、差集等数学运算
- 既然有了列表、元组这些数据容器,python设计者为什么还提供集合这样的数据类型呢?
- 在项目中,我们可能有这样的需求:需要记录一些数据,而这些数据必须保证是不重复的,而且数据的顺序并没有要求,就可以考虑使用集合
- 回顾:列表、元组的元素是可以重复,而且有序
(2)集合的定义
- 集合的定义:创建一个集合,只要用逗号分隔的不同的数据项,并使用{}括起来即可,示例如下
set_a = {100,200,300,400,500} basket = {'apple','orange','pear','banana'} - 集合基本使用案例:
set_a = {100,200,300,400,500} basket = {'apple','orange','pear','banana'} print(f"set_a的内容是:{set_a} 类型是:{type(set_a)}")
(3)注意事项和使用细节
- 集合是由不重复元素组成的无序容器
- 不重复元素组成,可以理解为会自动去重
- 无序:也就是你定义的元素的顺序和取出的顺序不能保证一致
- 集合底层会按照自己的一套算法来存储和取出数据,所以每次取出顺序是不变的
basket = {'apple', 'orange', 'apple', 'pear', 'orange','banana'} print(f"basket:{basket}") set_a = {100,200,300,400,500} print(f"set_a:{set_a}") print(f"set_a:{set_a}") print(f"set_a:{set_a}")
- 集合不支持索引
- 既然集合不支持索引,所以对集合进行遍历不支持while,只支持for
print("=" * 30) basket = {"apple", "orange", "apple", "pear", "orange","banana"} for ele in basket: print(ele) - 创建空集合只能用set(),不能用{},{}创建的是空字典
set_b = {} set_c = set() print(f"set_b:{set_b} 类型:{type(set_b)} set_c:{set_c} 类型:{type(set_c)}")
(4)集合常用操作
| 序号 | 操作 |
|---|---|
| 1 | len(集合):集合元素个数 |
| 2 | x in s:检测 x 是否为 s 中的成员 |
| 3 | add(elem):将元素 elem 添加到集合中 |
| 4 | remove(elem):从集合中移除元素 elem。如果 elem 不存在于集合中则会引发 KeyError |
| 5 | pop():从集合中移除并返回任意一个元素。如果集合为空则会引发 KeyError |
| 6 | clear():从集合中移除所有元素 |
| 7 | union(*others) set | other | … :返回一个新集合,其中包含来自原集合以及 others 指定的所有集合中的元素 |
| 8 | intersection(*others) set & other & …:返回一个新集合,其中包含原集合以及 others 指定的所有集合中共有的元素 |
| 9 | difference(*others) set - other - … :返回一个新集合,其中包含原集合以及 others 指定的其他结合中不存在的元素 |
basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
# len(集合):集合元素个数
print("basket的元素个数:",len(basket))
# x in s:检测x是否为s中的成员
# 需求:判断apple是否在集合中
print("apple" in basket)
# add(elem):将元素elem添加到集合中
# 需求:将grape添加到集合中
basket.add("grape")
print(f"basket的元素:",basket)
# remove(elem):从集合中移除元素elem。如果elem不存在于集合中则会引发KeyError
# 需求:将apple从集合中删除
basket.remove("apple")
print(f"basket的元素:",basket)
# pop():从集合中移除并返回任意一个元素。如果集合为空则会引发KeyError
ele = basket.pop()
print("ele:",ele," 类型是:",type(ele))
print(f"basket的元素:",basket)
# clear():从集合中移除所有元素
# union(*others) set | other | ... :
# 返回一个新集合,其中包含来自原集合以及 others 指定的所有集合中的元素
books_1 = {"天龙八部", "笑傲江湖"}
books_2 = {"雪山飞狐", "神雕侠侣", "天龙八部"}
books_3 = books_1.union(books_2)
books_3 = books_1 | books_2 # 等价于上一行代码
print("books_3:", books_3)
# intersection(*others) set & other & ...:
# 返回一个新集合,其中包含原集合以及 others 指定的所有集合中共有的元素
books_4 = books_1.intersection(books_2)
books_4 = books_1 & books_2
print("books_4:", books_4)
# difference(*others) set - other - ... :
# 返回一个新集合,其中包含原集合中在others指定的其他集合中不存在的元素
books_5 = books_1.difference(books_2)
books_5 = books_1 - books_2
print("books_5:", books_5)
(5)集合生成式
- 集合生成式就是“生成集合的公式”
- 基本语法:
{集合元素的表达式 for 自定义变量 in 可迭代对象} {ele * 2 for ele in range(1,5)} ==> 得到集合含有2,4,6,8这四个元素 但是集合是无序的,所以不能保证元素的顺序一定是2,4,6,8
(6)课堂练习题
# 定义3个集合
s_history = {"小明", "张三", "李四", "王五", "Lily", "Bob"}
s_politic = {"小明", "小花", "小红", "二狗"}
s_english = {"小明", "Lily", "Bob", "Davil", "李四"}
# 求选课学生共有多少人
# 1.对三个集合求并集
# 2.对新的集合求len()
total = s_history | s_politic | s_english
print(f"选课学生共有{len(total)}人")
# 求只选了一门学科的学生数量和学生姓名
# 1.求出只选择history的学生
s1 = s_history - s_politic - s_english
# 2.求出只选择politic的学生
s2 = s_politic - s_history - s_english
# 3.求出只选择english的学生
s3 = s_english - s_history - s_politic
print(f"只选了一门学科(history)的学生数量 {len(s1 | s2 | s3)}和学生姓名 {s1 | s2 | s3}")
# 求只选了第一个学科(history)的学生数量和学生姓名
print(f"只选了第一个学科(history)的学生数量 {len(s1)}和学生姓名 {s1}")
# 求选了三门学科的学生数量和学生姓名
total_three = s_history & s_politic & s_english
print(f"选了三门学科的学生数量 {len(total_three)}和学生姓名 {total_three}")
八、字典(dict)
(1)先看一个需求
一个公司有多个员工,请使用合适的数据类型保存员工的信息(比如员工号、年龄、名字、入职时间、薪水等),要求
- 员工号是入职时分配的,唯一不重复
- 通过员工号,可以查询到员工的信息
- 根据需要,可以动态的增加、删除员工
- 根据需要,可以修改员工的信息(比如年龄、名字、入职时间、薪水等)
(2)基本介绍
- 字典(dict,完整的单词是dictionary)也是一种常用的Python数据类型,其他语言可能把字典称为联合内存或联合数组
- 字典是一种映射类型,非常适合处理通过xx查询yy的需求,这里的xx我们称为Key(键/关键字),这里的yy我们称为Value(值),即Key--Value的映射关系
(3)字典的定义
- 创建一个字典,只要把逗号分隔的不同的元素,用{}括起来即可,存储的元素是一个个的:键值对
dict_a = {key:value,key:value,key:value......} - 通过key取出对应的value语法 字典名[key] - 字典使用示例:
tel = {'jack':4098,'tom':4139} print(f"dict_tel:{tel} 类型:{type(tel)}") # 查询jack的tel print("jack的tel:",tel["jack"])
(4)注意事项和使用细节
- 字典的Key(关键字)通常是字符串或者数字,Value可以是任意数据类型
dict_a = { "jack":[100,200,300], "mary":(10,20,"hello"), "nono":{"apple","pear"}, "smith":"计算机老师", "周星驰":{ "性别":"男", "age":18, "地址":"香港" } } print(f"dict_a:{dict_a} 类型:{type(dict_a)}") - 字典不支持索引,会报错
- 既然字典不支持索引,所以对字典进行遍历不支持while,只支持for,注意直接对字典进行遍历,遍历得到的是Key
dict_b = {'one':1,'two':2,'three':3} # 遍历方式1-依次取出key,再通过dict[key]取出对应的value print("==========遍历方式1==========") for key in dict_b: print(f"key:{key} value:{dict_b[key]}") # 遍历方式2-依次取出value print("==========遍历方式2==========") for value in dict_b.values(): print(f"value:{value}") # 遍历方式3-依次取出key-value print("==========遍历方式3==========") for k,v in dict_b.items(): print(f"key:{k} value:{v}") - 创建空字典可以通过{},或者dict()
dict_c = {} dict_d = dict() print(f"dict_c:{dict_c} 类型是:{type(dict_c)}") print(f"dict_d:{dict_d} 类型是:{type(dict_d)}") - 字典的key必须是唯一的,如果你指定了多个相同的key,后面的键值对会覆盖前面的
dict_e = {'one':1,'two':2,'three':3,'two':200} print(f"dict_e:{dict_e}")
(5)字典常用操作
| 序号 | 操作 |
|---|---|
| 1 | len(d):返回字典d中的项数 |
| 2 | d[key]:返回d中以key为键的项。如果映射中不存在key,则会引发KeyError |
| 3 | d[key]=value:将d[key]设为value,如果key已经存在,则是修改value,如果key没有存在,则是增加key-value |
| 4 | del d[key]:将d[key]从d中移除。如果映射中不存在则会引发KeyError |
| 5 | pop(key[,default]):如果key存在于字典中则将其移除,并返回其值,否则返回default。如果default未给出且key不存在于字典中,否则会引发KeyError |
| 6 | keys():返回字典所有的key |
| 7 | key in d:如果d中存在键key则返回True,否则返回False |
| 8 | clear():移除字典中的所有元素 |
dict_a = {'one':1,'two':2,'three':3}
# len(d):返回字典d中的项数
print(f"dict_a 的元素个数是:{len(dict_a)}")
# d[key]:返回d中以key为键的项。如果映射中不存在key则会引发KeyError
print(f"key为three对应的value:{dict_a['three']}")
# d[key] = value:将d[key]设为value,如果key已经存在,则是修改value,
# 如果key没有存在,则是增加key-value
# 修改 需求:修改key = 'one'对应的value为“第一”
dict_a['one'] = "第一"
print(f"dict_a:{dict_a}")
# 添加 需求:增加key为'four',value为4
dict_a['four'] = 4
print(f"dict_a:{dict_a}")
# del d[key]:将 d[key] 从d中移除。如果映射中不存在key,则会引发KeyError
# 需求 删除key为'four'的元素
del dict_a['four']
print(f"dict_a:{dict_a}")
# pop(key [, default]):
# 如果 key 存在于字典中则将其移除并返回其值,否则返回 default。
# 如果 default 未给出且 key 不存在于字典中,则会引发 KeyError
# 需求:将key为'one'的值返回,并将该元素从字典移除
val = dict_a.pop('one')
print(f"val:{val}")
print(f"dict_a:{dict_a}")
# keys():返回字典所有的 key
dict_a_keys = dict_a.keys()
print(f"dict_a_keys:{dict_a_keys} 类型是:{type(dict_a_keys)}")
for k in dict_a_keys:
print("k->",k)
# key in d:如果 d 中存在键 key 则返回 True,否则返回 False
# 需求:判断字典中是否有key 'two'
print("two" in dict_a)
# clear():移除字典中的所有元素
# 需求:将字典清空
dict_a.clear()
print(f"dict_a:{dict_a}")
(6)字典生成式
- 看一个具体需求:
# 给出了如下两个列表: books = ["红楼梦","三国演义","西游记","水浒传"] authors = ["曹雪芹","罗贯中","吴承恩","施耐庵"] # 生成对应的字典 dict_book = {book:author for book,author in zip(books,authors)} print(f"dict_book:{dict_book}") - 内置函数zip():
- 说明:zip()可以将可迭代的对象作为参数,将对象中对应的元素打包成一个元组,返回由这些元组组成的列表
- 字典生成式的基本语法:
{字典key的表达式:字典value的表达式 for 表示key的变量,表示value的变量 in zip(可迭代对象,可迭代对象)}
- 再举一个案例:
# 给出两个列表 english_list = ["red","black","yellow","white"] chinese_list = ["红色","黑色","黄色","白色"] # 生成一个字典 dict_color = {chinese:english.upper() for chinese,english in zip(chinese_list,english_list)} print(f"dict_color:{dict_color}")
(7)课堂练习
# 一个公司有多个员工,请使用合适的数据类型保存员工信息(员工号、年龄、姓名、入职时间、薪水)
clerks = {
"0001": {
"age": 20,
"name": "贾宝玉",
"entry_time": "2011-11-11",
"salary": 12000
},
"0002": {
"age": 21,
"name": "薛宝钗",
"entry_time": "2015-12-12",
"salary": 10000
},
"0010": {
"age": 18,
"name": "林黛玉",
"entry_time": "2018-10-10",
"salary": 20000
}
}
# 通过员工号(0010),可以查询到员工的信息
print(f"员工号为0010的信息为:姓名-{clerks ['0010']['name']} "
f"年龄-{clerks ['0010']['age']} "
f"入职时间-{clerks ['0010']['entry_time']} "
f"薪水-{clerks ['0010']['salary']}")
# 增加:(员工号:0020,年龄:30,名字:老韩,入职时间:2020-08-10,薪水:6000)
clerks['0020'] = {
"age": 30,
"name": "老韩",
"entry_time": "2020-08-10",
"salary": 6000
}
print("clerks:", clerks)
# 删除:0001号员工
del clerks ['0001']
print("-" * 60)
print("clerks:", clerks)
# 修改 员工号为0020的,名字:韩顺平,入职时间:1999-10-10,薪水在原来的基础上增加10%
clerks['0020']['name'] = "韩顺平"
clerks['0020']['entry_time'] = "1999-10-10"
clerks['0020']['salary'] *= 1.1
print("-" * 60)
print("clerks:", clerks)
# 要求:遍历所有员工,把所有员工的薪水,在原工资的基础上,增加20%
keys= clerks.keys()
for key in keys:
clerks[key]['salary'] *= 1.2
print("-" * 60)
print("clerks:", clerks)
九、小结
(1)数据容器特点比较
| 比较项 | 列表(list) | 元组(tuple) | 字符串(str) | 集合(set) | 字典(dict) |
|---|---|---|---|---|---|
| 是否支持多个元素 | Y | Y | Y | Y | Y |
| 元素类型 | 任意 | 任意 | 只支持字符 | 任意 | Key:通常是字符串或者数字,Value:任意 |
| 是否支持元素重复 | Y | Y | Y | N | Key:不能重复,Value:可以重复 |
| 是否有序 | Y | Y | Y | N | 3.6版本之前是无序的,3.6之后开始支持元素有序的功能 |
| 是否支持索引 | Y | Y | Y | N | N |
| 可修改性/可变性 | Y | N | N | Y | Y |
| 使用场景 | 可修改、可重复的多个数据 | 不可修改、可重复的多个数据 | 字符串 | 不可重复的多个数据 | 通过关键字查询对应数据的需求 |
| 定义符号 | [] | () | "" | {} | {key:value} |
(2)数据容器操作小结
- 通用序列操作
运算 结果 x in s 如果 s 中的某项等于 x 则结果为 True,否则为 False x not in s 如果 s 中的某项等于 x 则结果为 False,否则为 True s + t s 与 t 相拼接 s*n 或 n*s 相当于 s 与自身进行 n 次拼接 s[i] s 的第 i 项,起始为 0 s[i: j] s 从 i 到 j 的切片 s[i: j: k] s 从 i 到 j 步长为 k 的切片 len(s) s 的长度 min(s) s 的最小项 max(s) s 的最大项 s.index(x [, i[, j]]) x 在 s 中首次出现的索引号(索引号在 i 或其后且在 j 之前) s.count(x) x 在 s 中出现的总次数 - 通用转换操作
str_a = "hello" list_a = ["jack", "tom", "mary"] tuple_a = ("hsp", "tim") set_a = {"red", "black"} dict_a = {"0001": "小倩", "0002": "黑山老妖"} # list([iterable]): # iterable可以是序列、支持迭代的容器或其他可迭代对象, # 也就是将指定的容器转成列表 print("-" * 60) print(f"str_a转成list:{list(str_a)}") print(f"tuple_a转成list:{list(tuple_a)}") print(f"set_a转成list:{list(set_a)}") print(f"dict_a转成list:{list(dict_a)}") # str(容器):将制定的容器转为字符串 print("-" * 60) print(f"list_a转成str:{str(list_a)}") print(f"tuple_a转成str:{str(tuple_a)}") print(f"set_a转成str:{str(set_a)}") print(f"dict_a转成str:{str(dict_a)}") # tuple([iterable]):iterable 可以是序列、支持迭代的容器或其他可迭代对象,<br />将指定的容器转成元组 print("-" * 60) print(f"str_a转成tuple:{tuple(str_a)}") print(f"list_a转成tuple:{tuple(list_a)}") print(f"set_a转成tuple:{tuple(set_a)}") print(f"dict_a转成tuple:{tuple(dict_a)}") # set([iterable]):iterable 可以是序列、支持迭代的容器或其他可迭代对象,<br />将指定的容器转成集合 print("-" * 60) print(f"str_a转成set:{set(str_a)}") print(f"list_a转成set:{set(list_a)}") print(f"tuple_a转成set:{set(tuple_a)}") print(f"dict_a转成set:{set(dict_a)}")序号 操作 1 list([iterable]):iterable 可以是序列、支持迭代的容器或其他可迭代对象,也就是将指定的容器转成列表 2 str(容器):将制定的容器转成字符串 3 tuple([iterable]):iterable 可以是序列、支持迭代的容器或其他可迭代对象,也就是将指定的容器转成元组 4 set([iterable]):iterable 可以是序列、支持迭代的容器或其他可迭代对象,也就是将指定的容器转成集合
更多推荐


所有评论(0)