2025-10-14
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.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')])
特点: 无序、可变、元素唯一(常用于去重)、支持数学集合运算。
底层原理: 哈希表。与字典类似,所以元素必须是不可变类型。
常用操作:
创建: 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))。集合的元素唯一性保证了去重。