Python学习笔记:第八站 是排还是散

Python学习笔记


课程笔记参考B站视频: Python全栈开发教程


第八站 是排还是散

本章介绍元组集合

1. 什么是元组

元组是Python内置的数据结构之一,是一个不可变序列。下面是不可变序列与可变序列的区别:

分类数据结构特点
不可变序列字符串、元组没有增、删,改的操作
可变序列列表、字典、集合可以对序列执行增、删、改操作,对象地址不发生更改

下面是代码示例:

'''
演示不可变序列与可变序列的区别
'''
print('-------展示不可变序列------')
str = 'hello'
print(id(str), str)
str += 'world'
print(id(str), str)
print('-------展示可变序列-------')
lst = [10,20,45]
print(id(lst), lst)
lst.append(50)
print(id(lst), lst)
  • 运行结果
-------展示不可变序列------
2313388674032 hello
2313388674480 helloworld
-------展示可变序列-------
2313388293120 [10, 20, 45]
2313388293120 [10, 20, 45, 50]

根据内存地址的变化可以看出,一旦修改了不可变序列的元素,其内存地址就会发生变化。

2. 元组的创建方式

元组使用小括号定义(列表使用方括号定义),元组内的元素对象也是使用逗号分隔开。元组的创建方式主要有两种:

  1. 直接使用小括号。
  2. 使用内置函数tuple()

下面是代码示例:

'''
元组的创建方式
'''
print('---------使用小括号--------')
tup1 = ('Python', 'hello', 100)
print(type(tup1), id(tup1), tup1)
tup2 = 'Python', 'hello', 100   # 可以省略小括号
print(type(tup2), id(tup2), tup2)
tup2 = ('python',)              # 若只有一个元素,要加上小括号和逗号
print(type(tup2), id(tup2), tup2)
print('---------使用tuple()------')
tup3 = tuple(('为了荣耀!', 'AI', 999.99))
print(type(tup3), id(tup3), tup3)
print('---------创建空元组--------')
tup4 = ()
print(type(tup4), id(tup4), tup4)
tup5 = tuple()
print(type(tup5), id(tup5), tup5)
  • 运行结果
---------使用小括号--------
<class 'tuple'> 2337434224704 ('Python', 'hello', 100)
<class 'tuple'> 2337434224704 ('Python', 'hello', 100)
<class 'tuple'> 2337433810016 ('python',)
---------使用tuple()------
<class 'tuple'> 2337433843904 ('为了荣耀!', 'AI', 999.99)
---------创建空元组--------
<class 'tuple'> 2337428537408 ()
<class 'tuple'> 2337428537408 ()

一定要注意,若元组只有一个元素,不管采用什么方式,都要加上小括号和逗号
有意思的是,由于元组是不可变序列,所以只要是元组的对象元素完全相同,那么就会指向相同的内存地址。

问题探讨:为什么要将元组设计成不可变序列?
因为不可变序列一旦创建成功,就不允许再进行增删改等操作。这样在多任务环境下,同时操作对象时不需要加锁。因此,在程序中尽量使用不可变序列。

注意事项:元组中存储的是对象的引用,需要注意:

a) 如果元组中对象本身不可变对象,则不能再引用其它对象。
b) 如果元组中的对象是可变对象,则可变对象的引用不允许改变,但数据可以改变。
即:顶层的引用逻辑禁止发生变化,下面的其他层可以变。

下面是代码示例:

tup1 = ('hello', [10,20], 963)
print(id(tup1), type(tup1),tup1)
print(id(tup1[0]), type(tup1[0]),tup1[0])
print(id(tup1[1]), type(tup1[1]),tup1[1])
print(id(tup1[2]), type(tup1[2]),tup1[2])
print('----------更改不可变对象-----------')
# tup1[0] = 20 # 报错:TypeError: 'tuple' object does not support item assignment
print(id(tup1[0]), type(tup1[0]),tup1[0])
print('----------更改可变对象-------------')
tup1[1][1] = 30         # 修改
print(id(tup1[1]), type(tup1[1]),tup1[1])
tup1[1].append('world') # 增加
print(id(tup1[1]), type(tup1[1]),tup1[1])
  • 运行结果
2302301489024 <class 'tuple'> ('hello', [10, 20], 963)
2302301489968 <class 'str'> hello
2302301109248 <class 'list'> [10, 20]
2302301206512 <class 'int'> 963
----------更改不可变对象-----------
2302301489968 <class 'str'> hello
----------更改可变对象-------------
2302301109248 <class 'list'> [10, 30]
2302301109248 <class 'list'> [10, 30, 'world']

3. 元组的遍历

元组是可迭代对象,所以元组的遍历有两种方法:

  1. 直接使用for…in进行遍历。
  2. 在保证不越界的情况下,使用索引遍历。

下面是代码示例:

tup1 = ('hello', [10, 20], 963)
print('---------直接使用for循环遍历---------')
for i in tup1:
   print(type(i), i)
print('---------使用for循环遍历索引---------')
for i in range(0,len(tup1),1):
   print(type(tup1[i]), tup1[i])
  • 运行结果
---------直接使用for循环遍历---------
<class 'str'> hello
<class 'list'> [10, 20]
<class 'int'> 963
---------使用for循环遍历索引---------
<class 'str'> hello
<class 'list'> [10, 20]
<class 'int'> 963

4. 什么是集合

集合也是Python语言提供的内置数据结构,与列表、字典一样都属于可变类型的序列。集合就是没有value的字典。 下面是集合的内存示意图,可以看出集合也是无序的。

5. 集合的创建

集合的创建同样也有两种方式:

  1. 直接使用 { } 。
  2. 使用内置函数set()

下面是代码示例:

print('----------使用花括号创建集合--------')
se1 = {'hello', 20.3, 56, 56} # 集合元素不允许重复
print(id(se1), type(se1), se1)
print('----------使用set()创建集合--------')
se2 = set(range(6))                             # 可迭代对象
print(id(se2), type(se2), se2)
se3 = set(range(6))
print(id(se3), type(se3), se3)
# 可以将迭代器对象、字符串、列表、元组、字典、集合都转化成集合的形式
se3 = set('hello')                              # 字符串
print('字符串:', id(se3), type(se3), se3)
se3 = set(['hello', 20.3, 56])                  # 列表
print('列表:', id(se3), type(se3), se3)
se3 = set(('hello', 20.3, 56))                  # 元组
print('元组:', id(se3), type(se3), se3)
se3 = set({'hello':'world', 20.3:20, 56:56.9})  # 字典
print('字典:', id(se3), type(se3), se3)
se3 = set({'hello', 20.3, 56})                  # 集合
print('集合:', id(se3), type(se3), se3)
print('----------元素不能为可变对象--------')
# se3 = set(['hello', 20.3, 56, [10,20]]) # TypeError: unhashable type: 'list'
# print('列表:', id(se3), type(se3), se3)
print('----------定义空集合---------------')
se4 = {}
print(id(se4), type(se4), se4)
se4 = set()     # 只能用set定义空集合
print(id(se4), type(se4), se4)
  • 运行结果
----------使用花括号创建集合--------
2497148610144 <class 'set'> {56, 20.3, 'hello'}
----------使用set()创建集合--------
2497148715744 <class 'set'> {0, 1, 2, 3, 4, 5}
2497148716640 <class 'set'> {0, 1, 2, 3, 4, 5}
字符串: 2497148716416 <class 'set'> {'h', 'o', 'e', 'l'}
列表: 2497148716640 <class 'set'> {56, 20.3, 'hello'}
元组: 2497148716416 <class 'set'> {56, 20.3, 'hello'}
字典: 2497148716640 <class 'set'> {56, 20.3, 'hello'}
集合: 2497148716864 <class 'set'> {56, 20.3, 'hello'}
----------元素不能为可变对象--------
----------定义空集合---------------
2497148298624 <class 'dict'> {}
2497148716640 <class 'set'> set()

通过上述代码也可以总结一下集合的特点(参考字典的特点):

  1. 集合中的所有元素不允许重复,否则会自动删除。
  2. 集合中的元素是无序的。
  3. 集合中的元素必须是不可变对象(比如列表就不可以)。
  4. 集合也可以根据需要动态地伸缩。
  5. 集合会浪费较大的内存,也是一种使用空间换时间的数据结构。
  6. 空集合的定义只能使用内置函数set()

6. 集合的增、删、查操作

分类集合方法操作描述
判断in 或 not in判断集合中是否包含某一元素
增加.add()一次添中一个元素
.update()一次至少添加一个元素
删除.remove()一次删除一个指定元素,如果指定的元素不存在抛出KeyError
.discard()一次删除一个指定元素,如果指定的元素不存在不抛异常
.pop()删除集合的第一个(地址最小的)元素
.clear()清空集合所有元素
del(内置函数)删除字典中一个键值对,必须添加索引

注意集合的判断操作就相当于对集合的元素进行了访问,而增加和删除操作就相当于对于集合的元素做出了修改。

下面是代码示例:

'''
展示集合的相关操作
'''
print('-----------集合的判断操作----------')
se1 = set(range(9))
print(id(se1), type(se1), se1)
print('9在集合中:', 9 in se1)
print('10不在集合中:', 10 not in se1)
print('-----------集合的增加操作----------')
se1.add(56.3)  # 若添加已有元素,什么也不会发生
print(id(se1), type(se1), se1)
se1.update(('hello', 100.3)) # 创建集合的所有类型都支持
print(id(se1), type(se1), se1)
print('-----------集合的删除操作----------')
se1.remove(56.3)
print(id(se1), type(se1), se1)
# se1.remove('world') # 删除不存在的元素:KeyError: 'world'
se1.discard(4)
print(id(se1), type(se1), se1)
se1.discard('world')   # 删除不存在的元素,不会报错
print(id(se1), type(se1), se1)
se1.pop()
print(id(se1), type(se1), se1)
se1.clear()
print(id(se1), type(se1), se1)
del se1  # 删除这个集合对象
  • 运行结果
-----------集合的判断操作----------
2092296431200 <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8}
9在集合中: False
10不在集合中: True
-----------集合的增加操作----------
2092296431200 <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8, 56.3}
2092296431200 <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8, 100.3, 'hello', 56.3}
-----------集合的删除操作----------
2092296431200 <class 'set'> {0, 1, 2, 3, 4, 5, 6, 7, 8, 100.3, 'hello'}
2092296431200 <class 'set'> {0, 1, 2, 3, 5, 6, 7, 8, 100.3, 'hello'}
2092296431200 <class 'set'> {0, 1, 2, 3, 5, 6, 7, 8, 100.3, 'hello'}
2092296431200 <class 'set'> {1, 2, 3, 5, 6, 7, 8, 100.3, 'hello'}
2092296431200 <class 'set'> set()

7. 集合的关系与数学操作

关系集合方法操作描述
相等== 或 !=判断两个集合是否相等
子集.issubset()判断一个集合是否是另一个集合的子集
超集.issuperset()判断一个集合是否是另一个集合的超集
交集.isdisjoint()判断两个集合是否没有交集

下面是代码示例:

print('------------判断是否相等----------')
se1 = set(range(6))
se2 = set(range(5,-1,-1))
print('se1:', se1)
print('se2:', se2)
print('是否相等?', se1 == se2) # 判断相等与定义是的顺序无关
print('---------判断是否子集、超集--------')
se1.pop()
print('se1:', se1)
print('se2:', se2)
print('se1是se2的子集?', se1.issubset(se2))
print('se1是se2的超集?', se1.issuperset(se2))
print('------------判断是否有交集---------')
print('se1:', se1)
print('se2:', se2)
print('两者没有交集吗?', se1.isdisjoint(se2))
  • 运行结果
------------判断是否相等----------
se1: {0, 1, 2, 3, 4, 5}
se2: {0, 1, 2, 3, 4, 5}
是否相等? True
---------判断是否子集、超集--------
se1: {1, 2, 3, 4, 5}
se2: {0, 1, 2, 3, 4, 5}
se1是se2的子集? True
se1是se2的超集? False
------------判断是否有交集---------
se1: {1, 2, 3, 4, 5}
se2: {0, 1, 2, 3, 4, 5}
两者没有交集吗? False

基于上述集合关系的基础上,便有如下集合的数学操作

描述集合方法&数学运算符操作描述
求交集.intersection() 或 &求两个集合的交集
求并集.union() 或 |合并两个集合的所有元素
求差集A.difference(B) 或 A-B集合A减去集合B
求对称差集.symmetric_difference() 或 ^两个集合的并集 减去 他们的交集

下面是代码示例:

'''
演示集合的数学操作
'''
se1 = set(range(6))
se2 = set(range(3,-3,-1))
print('-----------求交集-----------')
print('se1: ', id(se1), se1)
print('se2: ', id(se2), se2)
se3 = se1.intersection(se2)
print('交集:', id(se3), se3)
se3 = se1 & se2
print('交集:', id(se3), se3)
print('-----------求并集-----------')
print('se1: ', id(se1), se1)
print('se2: ', id(se2), se2)
se4 = se1.union(se2)
print('并集:', id(se4), se4)
se4 = se1 | se2
print('并集:', id(se4), se4)
print('-----------求差集-----------')
print('se1: ', id(se1), se1)
print('se2: ', id(se2), se2)
se5 = se1.difference(se2)
print('差集se1-se2:', id(se5), se5)
se5 = se1 - se2
print('差集se1-se2:', id(se5), se5)
se5 = se2.difference(se1)
print('差集se2-se1:', id(se5), se5)
se5 = se2 - se1
print('差集se2-se1:', id(se5), se5)
print('---------求对称差集---------')
print('se1: ', id(se1), se1)
print('se2: ', id(se2), se2)
se6 = se1.symmetric_difference(se2)
print('对称差集se1-se2:', id(se6), se6)
se6 = se1 ^ se2
print('对称差集se1-se2:', id(se6), se6)
se6 = se2.symmetric_difference(se1)
print('对称差集se2-se1:', id(se6), se6)
se6 = se2 ^ se1
print('对称差集se2-se1:', id(se6), se6)
print('---同一个方法产生的新集合地址相同---')
se2.add(100)
se7 = se1.symmetric_difference(se2)
print('对称差集se1-se2:', id(se7), se7)
se7 = se1 ^ se2
print('对称差集se1-se2:', id(se7), se7)
se7 = se2.symmetric_difference(se1)
print('对称差集se2-se1:', id(se7), se7)
se7 = se2 ^ se1
print('对称差集se2-se1:', id(se7), se7)
  • 运行结果
-----------求交集-----------
se1:  1738975405664 {0, 1, 2, 3, 4, 5}
se2:  1738975511264 {0, 1, 2, 3, -2, -1}
交集: 1738975512160 {0, 1, 2, 3}
交集: 1738975511936 {0, 1, 2, 3}
-----------求并集-----------
se1:  1738975405664 {0, 1, 2, 3, 4, 5}
se2:  1738975511264 {0, 1, 2, 3, -2, -1}
并集: 1738975512160 {0, 1, 2, 3, 4, 5, -1, -2}
并集: 1738975512384 {0, 1, 2, 3, 4, 5, -1, -2}
-----------求差集-----------
se1:  1738975405664 {0, 1, 2, 3, 4, 5}
se2:  1738975511264 {0, 1, 2, 3, -2, -1}
差集se1-se2: 1738975512160 {4, 5}
差集se1-se2: 1738975511712 {4, 5}
差集se2-se1: 1738975512160 {-2, -1}
差集se2-se1: 1738975511712 {-2, -1}
---------求对称差集---------
se1:  1738975405664 {0, 1, 2, 3, 4, 5}
se2:  1738975511264 {0, 1, 2, 3, -2, -1}
对称差集se1-se2: 1738975512160 {4, 5, -1, -2}
对称差集se1-se2: 1738975510816 {4, 5, -1, -2}
对称差集se2-se1: 1738975512160 {4, 5, -1, -2}
对称差集se2-se1: 1738975510816 {4, 5, -1, -2}
---同一个方法产生的新集合地址相同---
对称差集se1-se2: 1738975512160 {100, 4, 5, -2, -1}
对称差集se1-se2: 1738975511488 {100, 4, 5, -2, -1}
对称差集se2-se1: 1738975512160 {4, 5, 100, -2, -1}
对称差集se2-se1: 1738975511488 {4, 5, 100, -2, -1}

注意到:

  1. 上述所有的数学操作都是产生了一个新的集合,并不会对原来的集合产生影响。
  2. 若集合元素没变,由同一个操作(包括方法和数学运算符)生成的新集合地址相同(哪怕颠倒集合的操作顺序)。
  3. 若集合元素改变,那么由方法生成的新集合地址不变,但由数学运算符生成的新地址集合会改变。

8. 集合生成式

集合生成式的定义介于列表生成式与字典生成式之间(三者之间的关系如下图),它的标准格式如下:

{ 集合元素表达式 for 自定义变量 in 可迭代对象}
自定义变量换为键值对
花括号换成方括号
集合生成式
字典生成式
列表表达式

下面是代码示例:

se1 = {i**3 for i in range(-3,4)}
print(type(se1), se1)
  • 运行结果
<class 'set'> {0, 1, -27, 8, -8, 27, -1}

9. 元组、列表、字典、集合的总结

注:Python中没有元组生成式,因为元组是不可变序列。

性质元组(tuple)列表(list)字典(dict)集合(set)
可变序列?不可变可变可变可变
可重复?可重复可重复键不可重复
值可重复
不可重复
有序?有序有序无序无序
定义符号小括号 ( )方括号 [ ]花括号 { key:value }花括号 { }

对于 可变序列&不可变序列 来说,它们有一些通用的性质:

  1. 元素相同时,不可变序列会指向同一个内存,可变序列会开辟出不同的内存。
  2. 不可变序列的元素一旦修改,其指向的内存地址就会更改。但如果是对不可变序列中的可变对象进行增删改操作,其指向的内存地址不变,
  3. 不可变序列一旦创建成功,就不允许再进行增删改等操作。
  4. 有序序列都可以通过索引进行访问(正向索引和逆向索引),无序序列只能通过查找的方式访问。

10. 本章作业

1. 我的咖啡馆你做主

说明:

下面是代码示例:

'''演示元组的使用'''
coffee_name = ('蓝山', '卡布奇诺', '拿铁', '皇家咖啡', '女五咖啡', '美丽与哀愁')
print('您好!欢迎光临小喵咖啡屋')
print('本店经营的咖啡有:')
for index,item in enumerate(coffee_name):
   print(str(index+1) + '.' + item)

index= int(input('请输入您喜欢的咖啡编号:'))
if 0<=index<=len(coffee_name):
   print(f'您的咖啡[{coffee_name[index-1]}]好了,请您慢用')
else:
   print('您点的咖啡不存在,请下次光临')
  • 运行结果
您好!欢迎光临小喵咖啡屋
本店经营的咖啡有:
1.蓝山
2.卡布奇诺
3.拿铁
4.皇家咖啡
5.女五咖啡
6.美丽与哀愁
请输入您喜欢的咖啡编号:1
您的咖啡[蓝山]好了,请您慢用

2. 显示2019中超联赛前5名排行

说明:

下面是代码示例:

'''演示元组之中又包含一个元组'''
scores=(('广州恒大',72),('北京国安',70), ('上海上港',66), ('江苏苏宁',53), ('山东鲁能',51))
for index,item in enumerate (scores):
   print(str(index+1) + '.', end=' ')
   for i in item:
       print(i, end=' ')
   print()
  • 运行结果
1. 广州恒大 72 
2. 北京国安 70 
3. 上海上港 66 
4. 江苏苏宁 53 
5. 山东鲁能 51 

3. 模拟手机通信录

说明:

下面是代码示例:

'''演示集合的无序'''
phones = set()
for i in range(5): # 必须输入5个人
   info= input(f'请输入第{i+1}个朋友的姓名和手机号码:')
   phones.add(info)
for item in phones:
   print(item)
  • 运行结果
请输入第1个朋友的姓名和手机号码:张三1111111
请输入第2个朋友的姓名和手机号码:李四2222222
请输入第3个朋友的姓名和手机号码:王五3333333
请输入第4个朋友的姓名和手机号码:陈六4444444
请输入第5个朋友的姓名和手机号码:麻七5555555
麻七5555555
张三1111111
李四2222222
王五3333333
陈六4444444
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虎慕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值