元组(tuple):
元组是Python中的一中数据结构,也是一个序列
,与列表类似
,不同的是,元组是不可变
的,也就是说,元组中的元素一点定义赋值之后,则无法进行修改
tuple1 = (1, 2, 3, 4)
元组访问元素的方式和列表一样,可以通过下标进行访问
tuple1 = (1, 2, 3, 4) # tuple1 = 1,2,3,4
print(tuple1[0]) # 1
除了上述之外,元组还可以进行解包:
tuple1 = (1, 2, 3, 4)
a, b, c, d = tuple1
print(a, b, c, d) # 1 2 3 4
如上代码,多个变量会将元组中的多个元素进行分解赋值,也就是对应位置的元素赋值给对应位置的变量
*思考:
代码中变量个数与元组中的元素个数相同,能够解包赋值,如果不同呢?
tuple1 = (1, 2, 3, 4)
a, b, d = tuple1 # ValueError: not enough values to unpack (expected 5, got 4)
print(a, b, d) # 1 2 3 4
tuple1 = (1, 2, 3, 4)
a, b, c = tuple1 # ValueError: too many values to unpack (expected 3)
print(a, b, c)
这样是不是有点鸡肋,如果说我有一百个元素,但是我只是想要其中开始和结束的两个元素,那怎么办?难不成要定义一百个变量?
其实这里支持 * 表示通配:
tuple1 = (1, 2, 3, 4)
a, *b, c = tuple1
print(a, b, c) # 1 [2, 3] 4
如上:
意思就是说,在这个tuple1元组中,除了第一个和最后一个元素之外的所有元素,都保存在变量b中。
同理,可以这样:
tuple1 = (1, 2, 3, 4)
a, *b = tuple1
print(a, b) # 1 [2, 3, 4]
或者:
tuple1 = (1, 2, 3, 4)
*a, b = tuple1
print(a, b) # [1, 2, 3] 4
但是需要注意的是:
在一次解包中,*只能出现一次:
tuple1 = (1, 2, 3, 4)
*a, b, *c = tuple1 # SyntaxError: two starred expressions in assignment
print(a, b, c)
拓展
解包赋值可以通用到Python中的序列中,如列表,元组、和后面的字典、集合等
不过要注意的是字典解包稍有不同,待会进行演示
字典是另一种可变容器模型,且可存储任意类型对象。
以键-值对的形式进行存储,键值之间用冒号:隔开,多个键值对之间用逗号,隔开,整个字典包括在花括号{}中。
键唯一,值任意
键在整个字典中都是唯一的,是不会重复的。
而值可以是任意的数据类型。
注意:如果添加重复键的值,那么后者会覆盖前面的
查询性能好
因为字典是通过键-值的形式进行存储,那么只要知道键,则可以直接找到值。所以查询性能比较好。
储存性能相比较差
而相对的,字典存储的时候就需要键和值对应,所以存储性能相对较差
# 根据键取值
d = {"name": "jack", "age": 18, "gender": "男"}
print(d["name"]) # jack
d['name'] = 'tom'
print(d) # {'name': 'tom', 'age': 18, 'gender': '男'}
# dict()
d = dict([('name', 'tom')])
print(d) # {'name': 'tom'}
d1 = dict([['name', 'tom'], ['age', 18]])
print(d1) # {'name': 'tom', 'age': 18}
d3 = dict({('name', 'tom')})
print(d3) # {'name': 'tom'}
d4 = dict({('name', 'tom'), ('age', 18)})
print(d4) # {'name': 'tom', 'age': 18}
需要注意的是,
1、 必须是双值序列列表或集合。
2、集合中的双值序列只能数元组,不能是列表,如d4
len()
len()函数用来获取字典中的键值对个数,与之前的列表类似
in和not in
关键字in用来判断字典中是否包含指定的键
not in 则相反,与列表类似。
get(key,[默认值])
get()函数是通过键来获取字典中对应的值并返回
# get(key,默认值)
d = {"name": "jack", "age": 18, "gender": "男"}
res = d.get('name') # jack
res = d.get('class') # None
res = d.get('class', '班级') # 班级
如上代码所示:
如果在字典中,找到了键,则直接返回对应的值
如果没有找到对应的键,则返回None
如果指定了默认值(第二个参数),在没有找到对应结果的时候,返回指定默认值
# setdefault(key,[default])
d = {"name": "jack", "age": 18, "gender": "男"}
d.setdefault('class')
print(d) # {'name': 'jack', 'age': 18, 'gender': '男', 'class': None}
d = {"name": "jack", "age": 18, "gender": "男"}
d.setdefault('class', 2)
print(d) # {'name': 'jack', 'age': 18, 'gender': '男', 'class': 2}
d = {"name": "jack", "age": 18, "gender": "男"}
d.setdefault('age', 12)
print(d) # {'name': 'jack', 'age': 18, 'gender': '男'}
根据代码演示:
setdefault()函数可以向字典中添加键值对
需要注意的是:
1、如果不指定默认值,则添加指定的键,对应的值为None,否则值为指定的值
2、如果添加的键已经存在字典中,则不会对字典产生影响
# update()
d = {"name": "jack", "age": 18, "gender": "男"}
d2 = {"class": 2, "grade": "三"}
d.update(d2)
print(d) # {'name': 'jack', 'age': 18, 'gender': '男', 'class': 2, 'grade': '三'}
# del
d = {"name": "jack", "age": 18, "gender": "男"}
del d['age']
print(d) # {'name': 'jack', 'gender': '男'}
# popitem()
d = {"name": "jack", "age": 18, "gender": "男"}
d.popitem()
print(d) # {'name': 'jack', 'age': 18}
# pop(key[,默认值])
d = {"name": "jack", "age": 18, "gender": "男"}
res = d.pop('name')
print(res) # jack
print(d) # {'age': 18, 'gender': '男'}
d = {"name": "jack", "age": 18, "gender": "男"}
# res = d.pop('class') # KeyError: 'class'
res = d.pop('class', '指定值不存在')
print(res) # 指定值不存在
print(d) # {'name': 'jack', 'age': 18, 'gender': '男'}
# copy()
d = {"name": "jack", "age": 18, "gender": "男"}
d2 = d.copy()
print(d) # {'name': 'jack', 'age': 18, 'gender': '男'}
print(d2) # {'name': 'jack', 'age': 18, 'gender': '男'}
d2['name'] = 'tom'
print(d) # {'name': 'jack', 'age': 18, 'gender': '男'}
print(d2) # {'name': 'tom', 'age': 18, 'gender': '男'}
copy()函数,会将字典复制一份。并且两个字典完全独立,也就是修改其中一份不会影响另一份
clear()
清除字典,即将字典中的键值对全部清除,没什么好解释的
遍历字典
思考:我们遍历字典,要遍历的一般是值,
思考:我们如何获得值
获得所有的键,通过遍历键来遍历值
# keys()
d = {"name": "jack", "age": 18, "gender": "男"}
print(d.keys()) # dict_keys(['name', 'age', 'gender'])
for k in d.keys():
print(d[k])
# jack
# 18
# 男
d = {"name": "jack", "age": 18, "gender": "男"}
print(d.values()) # dict_values(['jack', 18, '男'])
for v in d.values():
print(v)
# jack
# 18
# 男
d = {"name": "jack", "age": 18, "gender": "男"}
print(d.items()) # dict_items([('name', 'jack'), ('age', 18), ('gender', '男')])
for item in d.items():
print(item)
# ('name', 'jack')
# ('age', 18)
# ('gender', '男')
# 通过之前说的解包改变代码
for k, v in d.items():
print(k, v)
# name jack
# age 18
# gender 男
字典的使用内容中说了copy()复制。说复制出来的两份字典互不影响,改变其中一个则另一个不会改变。
现在来看这一段代码
d = {'name': 'jack', 'friend': {'name': 'tom', 'age': 17}, 'age': 18}
d1 = d.copy()
print(d) # {'name': 'jack', 'friend': {'name': 'tom', 'age': 17}, 'age': 18}
print(d) # {'name': 'jack', 'friend': {'name': 'tom', 'age': 17}, 'age': 18}
# 这里改变其中项:friend:{'name': 'tom', 'age': 17}
d1['friend']['name'] = 'lucy'
print(d) # {'name': 'jack', 'friend': {'name': 'lucy', 'age': 17}, 'age': 18}
print(d1) # {'name': 'jack', 'friend': {'name': 'lucy', 'age': 17}, 'age': 18}
咦?不是说改变其中一个字典,不会影响另一份吗?怎么这里进行修改,另一份也跟着变了
这是因为copy()函数是进行浅复制。也就是浅层次的复制。
它只对d这个字典进行了复制,而d中的某一个项引用的又是另一个对象,但是此时的复制也只是将这一个项保存的引用地址复制了一份,并没有将指向的对象也复制一份。
所以导致d中的friend和d1中的friend指向的都是同一个地方,其中一个改变,另一个也会跟着改变
集合:set,
集合是多个元素放在一队对花括号{}中,元素之间用逗号,隔开
如:
s = {1, 2, 3, 4}
print(s) # {1, 2, 3, 4}
集合与列表十分相似,但也有以下不同点:
1、只能存储不可变对象
s = {'123', 'h', '就'}
print(s) # {'123', '就', 'h'}
s1 = {(1, 2, 3), (4, 5, 6)}
print(s1) # {(4, 5, 6), (1, 2, 3)}
s2 = {[1, 2, 3], [4, 5, 6]}
print(s2) # TypeError: unhashable type: 'list'
2、无序的
s = {20, 10, 1, 2, 3, 4}
print(s) # {1, 2, 3, 4, 10, 20}
3、不重复
s = {20, 10, 1, 2, 3, 4, 20, 10, 1, 2, 3, 4}
print(s) # {1, 2, 3, 4, 10, 20}
set()函数可以用来创建集合,或者将序列和字典转为集合
s = set()
print(s) # set()
t = (1, 2, 3)
s = set(t)
print(s) # {1, 2, 3}
l = [1, 2, 3]
s = set(l)
print(s) # {1, 2, 3}
d = {"name": "jack", "age": 18, "gender": "男"}
s = set(d)
print(s) # {'name', 'age', 'gender'}
注意:set()函数只能将字典的键转为集合
in 、 not in 和len()、update()、remove()、clear()
这三个用法与之前的一样,不做解释
add()
向集合中添加元素
s = {1, 2, 3}
s.add(4)
print(s) # {1, 2, 3, 4}
s1 = {1, 2, 3, 4, 5}
s2 = {3, 4, 5, 6, 7}
# 交集运算 &
# 两个集合中重复的元素
r = s1 & s2
print(r) # {3, 4, 5}
# 并集运算 |
# 两个集合进行合并
r = s1 | s2
print(r) # {1, 2, 3, 4, 5, 6, 7}
# 差集运算 -
# 前者集合有哪些元素不在后者集合中
r = s1 - s2
print(r) # {1, 2}
r = s2 - s1
print(r) # {6, 7}
# 异或集运算 ^
# 集合里面不相交的部分
r = s1 ^ s2
print(r) # {1, 2, 6, 7}
# print('s1 =',s1)
# print('s2 =',s2)
# print('r =',r)
# 返回的是布尔类型
# <= 检查一个集合是否是另一个集合的子集
# < 检查一个集合是否是另一个集合的真子集
# >=检查一个集合是否是另一个集合的超集
# >检查一个集合是否是另一个集合的真超集
a = {1, 2, 3}
b = {1, 2, 3, 4, 5}
c = {1, 2, 3, 4, 5}
print(a <= c) # True
print(a < c) # True
print(b <= c) # True
print(b < c) # False
可变对象与不可变对象
# 可变对象
# 可变对象,也就是说,改变对象中的其中一个值,变量所保存的对象并不会改变,依旧是原来的那个对象
# 不可变对象
# 与可比那对象相反,如果改变对象中的某一个值,那么对象就不是原来的对象
a = '123'
b = a
print(a, id(a)) # 123 2001426837944
print(b, id(b)) # 123 2001426837944
b = '124'
print(a, id(a)) # 123 2001426837944
print(b, id(b)) # 123 2001427673248
a = [1, 2, 3]
b = a
print(a, id(a)) # [1, 2, 3] 2001427667976
print(b, id(b)) # [1, 2, 3] 2001427667976
b[0] = 10
print(a, id(a)) # [10, 2, 3] 2001427667976
print(b, id(b)) # [10, 2, 3] 2001427667976
通过以上代码示例:
能够发现,当有两个对象同时指向一个值的时候(b=a)
在都没发生变化的时候,发现两个对象的id是一样的