Python中所有数据都是对象,分为可变(Mutable)和不可变(Immutable)。可变就是创建后值可以修改,而对象本身的内存地址不变(list、dict、set)。不可变就是创建后值不可以修改(int、float、str、bool、tuple),修改的话本身的内存地址会变化。作为函数参数时,不可变对象传递的是值(即使修改也只在函数内部),可变对象传递的是引用(函数内部修改会影响外部)。字典的键必须是不可变类型,因为字典需要计算键的哈希值来快速查找,可变对象哈希值可能变化,导致无法定位。
可变多方便,为什么会有不可变这种类型呢?主要原因如下:
- 安全性:比如字典的键或集合的元素,不可变的话其哈希值就会固定,确保了查找效率和一致性。
- 效率:许多字符串操作实际上是创建新字符串,避免了复杂的内存管理。
- 多线程安全:不可变性使其天然线程安全,无需额外锁机制。
a = 10
print(id(a))
a += 1
print(id(a)) # 发现地址变化,a是不可变类型
s = "hello"
print(id(s))
s += " world"
print(id(s)) # 发现地址变化,s是不可变类型
l = [1, 2]
print(id(l))
l.append(3)
print(id(l)) # 地址不变,l是可变类型
result:
140736140286680
140736140286712
3067395053136
3067395586608
3067392807296
3067392807296
1. 核心数据结构:列表 (list), 字典 (dict), 集合 (set)
1.1 列表 (List)
- 特点: 有序(元素有索引)、可变(可修改)、可存储任意类型数据。
- 底层原理: 动态数组。当列表扩容时,会重新分配更大的内存空间,并将旧元素复制过去。
- 常用操作:
- 创建:
my_list = [1, 'hello', True] - 访问:
my_list[0],my_list[-1](索引),my_list[1:3](切片) - 增:
append(item)(末尾添加),insert(index, item)(指定位置插入),extend(iterable)(合并另一个可迭代对象) - 删:
remove(value)(删除第一个匹配项),pop(index=None)(删除并返回指定索引项,默认末尾),del my_list[index](按索引删除),clear()(清空列表) - 改:
my_list[0] = 'new_value' - 查:
in运算符,count(item)(统计次数),index(item)(查找索引) - 排序:
sort()(原地排序),sorted(iterable)(返回新列表)
- 创建:
# ############列表##############
my_list = [1, 'hello', True] # 创建
print(my_list[1], my_list[-1], my_list[1:3]) # 索引切片 hello True ['hello', True]
# 增
my_list.append(my_list) # 整体添加 [1, 'hello', True, [...]]
print(my_list)
my_list.insert(0,0)
print(my_list)
my_list.extend(my_list) # 内部元素逐个添加 [0, 1, 'hello', True, [...], 0, 1, 'hello', True, [...]]
print(my_list)
# 删
my_list.remove(my_list) # 删除第一个匹配项 [0, 1, 'hello', True, 0, 1, 'hello', True, [...]]
print(my_list)
my_list.pop(0) # 删除并返回指定索引项 [1, 'hello', True, 0, 1, 'hello', True, [...]]
print(my_list)
del my_list[0] # 案索引删除 ['hello', True, 0, 1, 'hello', True, [...]]
print(my_list)
# 查
print("hello" in my_list) # True
print(my_list.count("hello")) # 2
print(my_list.index("hello")) # 查找第一个对应值的索引
# 排序
print(my_list.sort())
print(sorted(my_list))
注意点:
append(item):将 item 作为一个整体添加到列表末尾。extend(iterable):将 iterable 中的所有元素逐个添加到列表末尾。
del list[index]:根据索引删除元素,不返回值。remove(value):删除列表中第一个匹配的 value,不返回值。pop(index=None):根据索引删除元素,并返回被删除的元素。默认删除并返回最后一个。
1.2 字典 (Dictionary)
- 特点: 键值对存储、无序(Python 3.7+ 保持插入顺序)、可变、键必须是不可变类型且唯一。
- 底层原理: 哈希表(或散列表)。通过键的哈希值快速定位值,平均时间复杂度为 O(1)。所以字典查找特别快,查找时计算键的哈希值,然后根据哈希值定位到存储位置。因此键不可变,变了哈希值就变了,无法通过哈希值找到对应的键值对了。
- 常用操作:
- 创建:
my_dict = {'name': 'Alice', 'age': 30} - 访问:
my_dict['name'](直接访问,键不存在会报错),my_dict.get('city', 'Unknown')(安全访问,可设默认值,不存在会返回默认值而不是直接报错) - 增/改:
my_dict['new_key'] = 'new_value'(键不存在则增,存在则改) - 删:
del my_dict['key'],my_dict.pop('key')(删除并返回),my_dict.popitem()(随机删除并返回键值对),clear() - 视图:
keys(),values(),items()(返回可迭代的视图对象) - 合并:
update(another_dict)
- 创建:
# ############字典##############
my_dict = {'name': 'Tom', 'age': 10, 'city': 'Nanjing'} # 创建
# 访问
print(my_dict['city']) # Nanjing
# print(my_dict['home']) # 报错
print(my_dict.get('city')) # Nanjing
print(my_dict.get('home', "暂无此信息!")) # 暂无此信息!
# 增/改
my_dict['home'] = 'Beijing' #
print(my_dict.get('home', "暂无此信息!")) # Beijing
# 删
del my_dict['age']
print(my_dict.get('age', "暂无此信息!")) # 暂无此信息!
# print(my_dict.pop('city')) # Nanjing
print(my_dict.popitem()) # 3.7之后,末尾的键对值('home', 'Beijing')
# my_dict.clear() # 清楚所有元素
# 视图
print(my_dict.keys()) # dict_keys(['name', 'city'])
print(my_dict.values()) # dict_values(['Tom', 'Nanjing'])
print(my_dict.items()) # dict_items([('name', 'Tom'), ('city', 'Nanjing')])
# 合并:
my_dict.update({'home': 'Beijing'})
print(my_dict.items()) # dict_items([('name', 'Tom'), ('city', 'Nanjing'), ('home', 'Beijing')])
2.3 集合 (Set)
- 特点: 无序、可变、元素唯一(常用于去重)、支持数学集合运算。
- 底层原理: 哈希表。与字典类似,所以元素必须是不可变类型。
- 常用操作:
- 创建:
my_set = {1, 2, 3},empty_set = set()(不能用{},因为那是空字典) - 增:
add(item) - 删:
remove(item)(元素不存在会报错),discard(item)(元素不存在不报错),pop()(随机删除并返回一个元素),clear() - 集合运算:
union()或|(并集)intersection()或&(交集)difference()或-(差集)symmetric_difference()或^(对称差集)issubset(),issuperset(),isdisjoint()(子集、超集、无交集判断)
- 创建:
# ############集合##############
my_set = {1, 2, 3}
empty_set = set() # (不能用 {},因为那是空字典)
# 增
my_set.add("2")
print(my_set) # {1, 2, 3, '2'}
my_set.add(2) # 已有的再增加无反应
print(my_set) # {1, 2, 3, '2'}
# 删
# my_set.pop() # 似乎是删除第一个
# print(my_set) # {2, 3, '2'}
# my_set.remove("2")
# print(my_set) # {2, 3}
# my_set.discard(3)
# print(my_set) # {2}
# my_set.clear()
# print(my_set) # set()
# 集合运算:
a = empty_set.union(my_set)
print(a) # {'2', 1, 2, 3}
a.add(4)
print(a.intersection(my_set)) # {1, 2, 3, '2'}
my_set.add(5)
print(a.difference(my_set)) # {4} 仅仅是a中非交集元素
print(a.symmetric_difference(my_set)) # {4,5} 两个集合的非交集
print(a.issubset(my_set)) # False
print(my_set.issubset(a)) # True
print(a.issuperset(my_set)) # True
print(my_set.issuperset(a)) # False
print(my_set.isdisjoint(a)) # False
print(my_set.isdisjoint(empty_set)) # True
- 问题:如何快速对列表进行去重?
- 回答: 最简单高效的方法是将其转换为集合,再转回列表:
list(set(my_list))。集合的元素唯一性保证了去重。