元组(tuple)
- 元组是一个不可变序列(列表可变)
- 一般当我们希望这个数据不可变得时候使用元祖,其余情况使用列表
创建元组
first_tuple=() # -------空元组
print(first_tuple,type(first_tuple))
tuple=(1, 2, 3, 4, 5)
print(tuple[3]) # --------元组的查找,索引
single_tuple = 12, # -----单一元组的表现形式,后面加一个逗号
print(single_tuple,type(single_tuple))
more_tuple = 10, 20, 30, 40 # ----等同于(10, 20, 30, 40)
print(more_tuple,type(more_tuple))
# out:
# () <class 'tuple'>
# 4
# (12,) <class 'tuple'>
# (10, 20, 30, 40) <class 'tuple'>
注:如果元组不是空元组,它里面至少得有一个
元组的解包
- 解包指将元组中的每一个元素都赋值给一个变量
tuple = (1, 2, 3, 4, 5)
a, b, c, d, e = tuple
print('a=', a)
print('b=', b)
print('c=', c)
print('d=', d)
print('e=', e)
# out:
# a= 1
# b= 2
# c= 3
# d= 4
# e= 5
== 解包案例_1 ==
a=1
b=2
a, b = b, a
print('a=', a)
print('b=', b)
# out:
# a= 2
# b= 1
== 解包案例_2 ==
tuple = (10, 20, 30, 40)
a, b, c = tuple
print(a, b, c)
# ValueError: too many values to unpack (expected 3)
# 会报错,因为值比变量多
元组中有太多的值,而没有足够的变量,是不可以的
- 解包时,元组的元素数和变量数必须一致
tuple = (10, 20, 30, 40)
a, b, *c = tuple # ----*在C,*C会获取元组中的剩余元素
print(a, b, c)
a, *b, c = tuple # ---*在b,会获取元组中间剩余的元素,同理若在a,获取左边的剩余的
print(a, b, c)
print(a, *b, c)
# out:
# 10 20 [30, 40]
# 10 [20, 30] 40
# 10 20 30 40
- 当元素数量与元组数量不一致时,可以通过添加*,这样变量将会获取元组中剩余的元素
- 不能加两个*
可变对象
每个对象当中保存了3个数据
- id (标识)
- type (类型)
- value (值)
a = [1, 2, 3]
a[0] = 10
print(a)
a = [4, 5, 6]
# out:
# [10, 2, 3]
# [4, 5, 6]
下面用画图解释一下,计算机里数据是以什么样的形式存储的,其中的值和id是随便编的,计算机中存储数据是以二进制形式。
- a[0] = 10(改对象)
- 这个操作是通过变量修改对象里面的值
- 这种操作不会改变变量指向的对象
a = [1, 2, 3]
print('修改前:',a,id(a))
a[0] = 10
print('修改后:',a,id(a))
# 修改前: [1, 2, 3] 2347954688584
# 修改后: [10, 2, 3] 2347954688584
修改后value改变,id不变。
2. a = 4, 5, 6
- 这个操作是在给变量重新赋值
- 这种操作会改变变量的对象
a = [1, 2, 3]
print('修改前:',a,id(a))
a = [4, 5, 6]
print('修改后:',a,id(a))
# 修改前: [1, 2, 3] 1151107748424
# 修改后: [4, 5, 6] 1151107748936
变量改变
3.进一步理解
a = [1, 2, 3]
b = a
b[0] = 10
print('a=', a,id(a))
print('b=', b,id(b))
# a= [10, 2, 3] 2648971432520
# b= [10, 2, 3] 2648971432520
== 仔细看结果 ==
你会发现我明明只改了b,但a也变了,且它两的id相同,下面用画图的方式解释
当执行b = a时,并不是重新开辟一个新的区域存储b,b = a共用一块变量区域,且变量的值相同,都指向同一个对象,当b[0] = 10执行时,a也会改变。
- == & is
a = [1, 2, 3]
b = [1, 2, 3]
print(id(a), id(b))
print(a is b)
print(a == b)
# out:
# 2207159374408 2207159374920
# False
# True
此时是开辟了两个变量区域,两个对象,他们的值相等,但id不同
字典
- 表现形式 dict
- 字典是一种新的数据结构,称之为映射(mapping)
- 字典的作用是用来存储对象的容器
- 列表存储数据性能很好,但是查询数据性能很差
- 字典中每一个元素都有唯一的一个名字,通过这个名字可以快速查找到指定的元素
- 唯一的名字称之为键(key),通过key可以查找到value,称之为值(value)
- 所以字典,我们也称之为键值对(key:value)
- 每个字典可以有多个键值对,每一个键值对称之为一项(item)
创建字典
** 方法1 **
d = {'花果山':'美猴王', '盘丝洞':'蜘蛛精'}
print(d)
# {'花果山': '美猴王', '盘丝洞': '蜘蛛精'} <class 'dict'>
** 方法2 **
d = dict(name = '齐天大圣', location = '花果山')
print(d)
# {'name': '齐天大圣', 'location': '花果山'}
** 方法3 **
d = dict([('name', '齐天大圣'), ('location', '花果山')])
print(d)
# {'name': '齐天大圣', 'location': '花果山'}
双值子序列:
- 双值序列,序列中只有2个值,如[1, 2]
- 子序列,如果序列当中的元素也是序列,那么我们称这个元素为子序列,如[(1,2)]
字典中
- 值可以是任意对象
- 键可以是任意不可变的对象
- 字典的键是唯一的,如果重复后面的会替换前面的
获取字典中的值
d = {
'花果山':'美猴王',
'盘丝洞':'蜘蛛精',
'葫芦藤':'葫芦娃'
}
print(d['花果山'], d['盘丝洞'], d['葫芦藤'])
字典的使用
part_noe
d = {
'name':'美猴王',
'loction':'水帘洞'
}
print(d['name']) # ---通过键获得值
n = 'name'
print(d[n])
print(d.get('name'))
d['name'] = '齐天大圣'
print(d)
d['distance'] = 100000
print(d)
print(d.get('hello', '我不存在'))
print(len(d))
print('hello' in d)
# out:
# 美猴王
# 美猴王
# 美猴王
# {'name': '齐天大圣', 'loction': '水帘洞'}
# {'name': '齐天大圣', 'loction': '水帘洞', 'distance': 100000}
# 我不存在
# 3
# False
get()方法
- 获取数据的键不存在时,会返回None
- 可也以制定一个默认值,作为第二个参数,这样当获取不到键的时候会返回默认值
part_two
d = {
'name':'美猴王',
'location':'水帘洞'
}
d['location'] = '花果山'
d['phone'] = '123456'
print(d)
# {'name': '美猴王', 'location': '花果山', 'phone': '123456'}
d = {
'name':'美猴王',
'loction':'水帘洞'
}
r = d.setdefault('name','shell')
print('r=', r)
print(d)
# out:
# r= 美猴王
# {'name': '美猴王', 'loction': '水帘洞'}
# -----------------------
n = d.setdefault('phone','123456')
print(n)
print(d)
# out:
# 123456
# {'name': '美猴王', 'loction': '水帘洞', 'phone': '123456'}
你会发现第一次使用了setdefault()值没有改变
d.setdefault()
- setdefault可以用来向字典中添加键值对
- 如果key已经存在于字典中,则返回key值,不会做任何操作
- 如果key不存在,则向字典中添加这个key,并设置value,若不设置value,value为None
part_three
d1 = {'a':1,'b':2,'c':3}
d2 = {'b':4,'e':5,'f':6,'a':7}
d1.updata(d2)
print(d)
# {'a': 7, 'b': 4, 'c': 3, 'e': 5, 'f': 6}
原字典中没有则添加,有则覆盖
==part_four==
d = {'a': 7, 'b': 4, 'c': 3, 'e': 5, 'f': 6}
del d['a']
print(d)
n = d.popitem()
print(n)
print(d)
# {'b': 4, 'c': 3, 'e': 5, 'f': 6}
# ('f', 6)
# {'b': 4, 'c': 3, 'e': 5}
popitem()
- 随机删除字典当中的一个键值对,一般情况下都会删除最后一个键值对
- 删除后会将删除的key-value作为返回值
d = {'a': 7, 'b': 4, 'c': 3, 'e': 5, 'f': 6}
r = d.pop('b')
print(r)
print(d)
print(d.pop('name', 'python'))
print(d)
# 4
# {'a': 7, 'c': 3, 'e': 5, 'f': 6}
# python
# {'a': 7, 'c': 3, 'e': 5, 'f': 6}
pop()
- 根据key删除字典当中的key-value
- 返回的是删除的value
- 如果删除不存在的key,会报错keyError
- 如果指定了默认值,删除不存在的key时,会返回你所指定的值,但原序列不改变
浅拷贝(浅复制)
copy()用于对字典进行一个浅复制
d = {'a':1, 'b':2, 'c':3}
d2 = d.copy() # copy和d2 = d是有区别的,但效果是一样的
d2['a'] = 10
print('d=', d, id(d))
print('d2=', d2, id(d2))
# d= {'a': 1, 'b': 2, 'c': 3} 2138526181720
# d2= {'a': 10, 'b': 2, 'c': 3} 2138526181800
复制在内存中开辟了新的区域,那么什么是浅复制呢?
d = {'a':{'name':'悟空', 'age':'500'}, 'b':6, 'c':7}
d2 = d.copy()
d2['a']['name'] = '美猴王'
print('d=', d, id(d))
print('d2=', d2, id(d2))
# d= {'a': {'name': '美猴王', 'age': '500'}, 'b': 6, 'c': 7} 3045572274600
# d2= {'a': {'name': '美猴王', 'age': '500'}, 'b': 6, 'c': 7} 3045572275400
- 根据d2[‘a’] = 10的结果,我们可以看到d2的值变量,但d没变
- 但在使用d2[‘a’][‘name’] = '美猴王’时,d和d2的值都改变了
- 这就是浅复制,不会复制字典里的字典,它依然是按照在旧的变量里增加新的变量,相同值的逻辑
浅拷贝
- 只会复制字典本身,如果字典中还有字典是不会复制的
- copy()用于对字典进行一个浅复制
遍历字典
方法有3种
d = {'a':1, 'b':2, 'c':3}
print(d.keys())
for k in d,keys():
print(d[k])
# dict_keys(['a', 'b', 'c'])
# 1
# 2
# 3
- keys(),会返回字典所有的键
d = {'a':1, 'b':2, 'c':3}
print(d.values)
for i in d.values():
print(i)
# dict_values([1, 2, 3])
# 1
# 2
# 3
- values(),返回一个序列,序列中保存字典的值
d = {'a':1, 'b':2, 'c':3}
print(d.items())
d = {'a':1, 'b':2, 'c':3}
print(d.items())
for i,j in d.items():
print(i)
print(j)
# dict_items([('a', 1), ('b', 2), ('c', 3)])
# a
# 1
# b
# 2
# c
# 3
- items(),返回字典当中所有的项 它会返回一个序列 序列中包含双值子序列 双值分别是字典中的key-value