对变量的值进行修改时,变量对应的内存地址不变,对应的值发生了改变,这种数据类型就称为可变数据类型。
对变量的进行修改时,变量对应的内存地址发生了改变(变量指向了新的内存),从而修改了变量的值,而变量对应的原内存的值并没有被改变,这种数据类型就称为可变数据类型。
也就是:不可变数据类型更改后地址发生改变,可变数据类型更改地址不发生改变
数据类型 | 是否是可变数据类型 | 是否有序 |
---|---|---|
None (空) | 不可变 | - |
int (整数) | 不可变 | - |
float (浮点) | 不可变 | - |
bool (布尔) | 不可变 | - |
str (字符串) | 不可变 | - |
tuple (元组) | 不可变 | 序列类型,有序 |
list (列表) | 可变 | 序列类型,有序 |
set (集合) | 可变 | 序列类型,无序,不可重复 |
dict (字典) | 可变 | 映射类型,v3.6及以后无有序, 前面版本无序 |
数据类型 | 是否是可变数据类型 | 是否有序 | 说明 |
---|---|---|---|
bytes | 不可变 | - | 定义字节:b’hello’,bytes(5) |
bytearray | 可变 | - | 定义字节数组:bytearray(b’hello’), bytearray(10) |
complex (复数) | 不可变 | - | 由一个实数和一个虚数组合构成,如:4+3j |
frozenset (冻结的set) | 不可变 | 无序 | 冻结的set初始化后不能再添加或删除元素 |
array (数组) | 可变 | 有序 | 数组中的元素必须是同一类型 |
OrderedDict | 可变 | 有序 | key有序,setdefault取值key不存在也不报错 |
defaultdict | 可变 | 有序 | 取值时Key不存在也不会抛出KeyError异常 |
deque | 可变 | 有序 | 高效插入和删除的双向队列列表 |
list是可变、可重复的有序列表,里面的元素的数据类型也可以不同(也可以是另一个list)。list可根据索引号取其中的数据。
list1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
print("list1: ", list(list1)) # 输出: list1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
list2 = list(range(0, 10))
print("list2: ", list(list2))
list3 = [i*i for i in range(10) if i % 2 == 0]
print("list3: ", list(list3))
list4 = (str(i) + j for i in range(0, 10, 2) for j in "xyz")
print("list4: ", list(list4))
list1 = [0, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9]
list1.reverse() # 元素顺序反转
print("list reverse: ", list1)
list1.sort(reverse=False) # 排序
print("list sort: ", list1)
list1 = sorted(list1, reverse=True)
print("list sort: ", list1)
times = list1.count(5) # 查看list中的元素出现的次数
print("times: ", times)
list1.append(10)
print("append value: ", list1) # 添加元素
list1.insert(1, 10) # 在指定位置添加元素
print("insert value: ", list1)
list1.remove(10) # 删除指定value元素(第一个匹配的元素)
print("remove value: ", list1)
value = list1.pop(12) # 删除指定index的元素并返回删除的值
list1.pop() # 不指定index时默认删除最后一个元素
list1.pop(-2) # 删除倒数第二个元素
print("remove index: ", list1)
index_value = list1.index(3) # 查找第一个value为100的index值,如果不存在报TypeError异常
print("index_value: ", index_value)
print(list1)
index_value = list1.index(5, 7, 9) # 指定范围,从第7(包括)个到第9(不包括)个元素之间查找value为5的index
print("index_value: ", index_value)
list2 = [100, 101, 102]
# list1 = list1 + list2
list1.extend(list2)
print(list1)
print("*" * 10)
for value in list1:
print("value: %i" % value)
print("*" * 50)
for index in range(len(list1)):
print("index: %i, value: %i" % (index, list1[index]))
print("*" * 50)
for index, value in enumerate(list1):
print("index: %i, value: %i" % (index, value))
print("*" * 50)
for index, value in enumerate(list1, 100): # index从100开始
print("index: %i, value: %i" % (index, value))
elements = list1[0:3] # 取第0到3条元素(包括头不包括尾)
# elements = list1[:3]
print("slice elements: ", elements)
elements = list1[1:] # 取第1到最后一个元素(包括头也包括尾)
print("slice elements: ", elements)
elements = list1[-2] # 取倒数第二条
print("slice elements: ", elements)
elements = list1[4:-2] # 取第四条到倒数第二条(包括头不包括尾)
print("slice elements: ", elements)
elements = list1[0:6:2] # 取第0条到第6条中每2个取一个
print("slice elements: ", elements)
elements = list1[:] # 取所有元素
print("slice elements: ", elements)
列表、元组和字符串都可以使用切片进行操作
# 浅拷贝只拷贝了引用,没有拷贝内容
list2 = list1
list2[1] = 1000
print("list1: ", list1)
print("list2: ", list1)
print(id(list1), id(list2))
# 深拷贝是对于一个对象所有层次的拷贝(递归拷贝)
list3 = list1.copy()
# import copy
# list3 = copy.copy(list1)
# list3 = copy.deepcopy(list1)
list1[1] = 1
print("list1: ", list1)
print("list3: ", list3)
print(id(list1), id(list3))
set是可变、不可重复的无序列表。 set中不可以放入可变对象,因为无法判断两个可变对象是否相等而去重。
set0 = {0, 0, 1, 2, 3, 4, 5, 4, 5, 6} # 直接定义set集合
print("set0: ", set0) # 输出 set0: {0,1, 2, 3, 4, 5, 6}
set1 = set([0, 0, 1, 2, 3, 4, 5, 4, 5, 6]) # 通过list定义set
print("set1: ", set1)
set2 = set((0, 0, 1, 2, 3, 4, 5, 4, 5, 6)) # 通过tuple定义set
print("set2: ", set2)
set3 = set({"x": 2, 10: "b"}) # 通过dict定义set
print("set3: ", set3) # 输出 set3: {10, 'x'}
my_list = [0, 0, 1, 2, 3, 4, 5, 4, 5]
set4 = set(my_list) # set中不可以放入可变对象,然而为何放入list却不报错?
print("set4: ", set4) # 输出 set4: {0, 1, 2, 3, 4, 5, 6}
# 由下面操作可以得出结论,set是先把list做遍历得到不可变的int对象类型后再放入set中
my_list[0] = 10
print("set4 with my_list changed: ", set4) # 输出 {0, 1, 2, 3, 4, 5, 6}
my_list.append([10, 20])
print("my_list: ", my_list)
set5 = set(my_list) # 在list再放入list,此时将报错
print("set5: ", set5)
set0 = {0, 0, 1, 2, 3, 4, 5, 4, 5, 6}
print("set0: ", set0)
set0.add("cn") # 添加单个元素
print("set0: ", set0)
set0.update([10, 20, 30]) # 添加多个元素
print("set0: ", set0)
set0.add(("com", "cn")) # 添加元组(元组是不可变数据类型)
print("set0: ", set0)
# set0.add([10, 20]) # 添加list报错,不能添加可变的数据类型(不能添加,但可以使用list创建set)
# set0.add({10, 20}) # 添加set报错,(可是使用不可变的frozenset添加:set0.add(frozenset({10, 20})))
# set0.add({"x": 2, 10: "b"}) # 添加dict报错,不能添加可变的数据类型(不能添加,但可以使用dict创建set)
set0.remove("cn") # 根据值删除元素(set不能根据索引删除)
print("set0: ", set0)
set1 = {"a", "b", 4, 6, 100}
my_set = set0 | set1 # 取并集
print(my_set)
my_set = set0 & set1 # 取交集
print(my_set)
注:set的遍历同list
dict是无序,key不可重复、不可变内容以key-value键值对形式存在的映射
dict中的key只能是不可变对象且唯一, 一个key对应一个value,多次对一个key设置value,后面的值会把前面的冲掉。
dict一般用在需要高速查找的很多地方。dict的key必须是不可变对象,这是因为dict根据key来计算value的存储位置,如果每次计算相同的key得出的结果不同,那dict内部就完全混乱了。这种通过key计算位置的算法称为哈希算法(Hash)。要保证hash的正确性,作为key的对象就不能变。在Python中,字符串、整数等都是不可变的,因此,可以放心地作为key。而list、set是可变的,所以就不能作为key。
dict1 = {"addr": "北京", "age": 18, "gender": "女"}
dict1["height"] = 1.77 # 添加元素
dict1.pop("age") # 删除元素输出
item_del = dict1.popitem() # 产出dict中的最后一个item并返回
print("item_del: ", item_del)
dict1["addr"] = "深圳" # 修改元素
print("dict1: ", dict1)
keys = dict1.keys() # 获取dict的所有key
print("keys: ", keys) # dict_keys(['add', 'height'])
addr = dict1.get("addr") # 根据key获取value,若key不存在报异常(defaultdict字典不报异常)
print("addr: ", addr)
addr = dict1.setdefault("addr") # 根据key获取value,若key不存返回None,也可设置默认返回值
print("addr: ", addr)
name = dict1.get("name", "unknow") # 根据key获取value,若key不存返回默认值'unknow'
print("name: ", name)
# dict的遍历
for key in dict1:
print("key: %s, value: %s" % (key, dict1[key]))
print("*" * 50)
for value in dict1.values():
print("value: ", value)
print("*" * 50)
for key, value in dict1.items():
print("key: %s, value: %s" % (key, value))
dict2 = {"mobel": 15888888888, "postal_code": 10000} # 合并两个dict
dict1.update(dict2)
print("dict1: ", dict1)
list查找和插入的时间随着元素的增加而增加;
占用空间小,浪费内存很少
dict查找和插入的速度极快,不会随着key的增加而变慢;
需要占用大量的内存,内存浪费多。
所以,dict是用空间来换取时间的一种方法。
# dict排序
dict3 = {'sh': 3, 'hz': 2, 'tj': 1, 'bj': 5, 'gz': 2, 'sz': 4, 'wh': 1}
# 默认排序,并仅返回key
key_rank1 = sorted(dict3.keys(), reverse=False)
print("key_rank1: ", key_rank1)
# 默认排序(以key来排序),并返回key和value
dict_key_rank1 = sorted(dict3.items(), reverse=False)
print("dict_key_rank1: ", dict_key_rank1)
# 以key排序
dict_key_rank2 = sorted(dict3.items(), key=lambda item: item[0], reverse=False)
print("dict_key_rank2: ", dict_key_rank2)
# 以value排序
dict_value_rank1 = sorted(dict3.items(), key=lambda item: item[1], reverse=False)
print("dict_value_rank1: ", dict_value_rank1)
# 以value排序
dict4 = {'上海': 3, '杭州': 2, '天津': 1, '北京': 5, '广州': 2, '深圳': 4, '武汉': 1}
dict_value_rank2 = sorted(dict4.items(), key=lambda item: item[1], reverse=True)
print("dict_value_rank2: ", dict_value_rank2)
tuple是不可变、有序的列表,所以一般在定义tuple时就进行初始化赋值。
注意:
在定义只有一个元素的tuple时其元素后面要加逗号
tuple0 = () # 创建空元祖
tuple0 = (1) # 不是tuple,会当成括号处理
tuple0 = (1,) # 正确的tuple
tuple虽然不可变但tuple中的元素对象却是可变的
my_list = ["x", "y"]
tuple1 = ('a', 'b', my_list) # tuple包含list,list变化时,tuple1也就跟着变化
print("tuple1: ", tuple1) # tuple1: ('a', 'b', ['x', 'y'])
my_list.append("z")
print("tuple1 with my_list changed: ", tuple1) # tuple1变为('a', 'b', ['x', 'y', 'z'])
tuple2 = (1, "good", 2, 3, "good", True) # 创建元组,里面的元素类型可以不同
tuple3 = ("a", "b", *tuple2, 4, 5) # 元组引用另一个数组中的所有元素
print("tuple3: ", tuple3)
element = tuple2[4] # 根据索引获取元组中的元素
element = tuple2[-2] # 使用索引获取元组中的元素
index = tuple2.index("good") # 获取第一个匹配给定值的index值
del tuple2 # 删除元组
# tuple2[4] = "well" # 修改元组的元素,报错
tuple4 = ("a", "b", 4, 5, [6, 7, 8])
print("tuple4: ", tuple4)
# tuple4[-1] = [10, 20, 30] #报错
tuple4[-1][0] = 100 # 可以通过修改元组中的list,从而改变元组
print("tuple4: ", tuple4) # tuple4: ('a', 'b', 4, 5, [100, 7, 8])
注:tuple的遍历同list