编辑
2024-06-20
Python
00

目录

Python 数据类型详解:可变与不可变、可哈希与不可哈希
一、数据类型分类表
可变与不可变
可哈希与不可哈希
可变与不可变
可变对象
不可变对象
可哈希与不可哈希
可哈希对象
不可哈希对象
二、可变与不可变对象
2.1 可变对象
优点:
缺点:
适用场景:
示例:
2.2 不可变对象
优点:
缺点:
适用场景:
示例:
三、可哈希与不可哈希对象
3.1 可哈希对象
优点:
缺点:
适用场景:
示例:
3.2 不可哈希对象
优点:
缺点:
适用场景:
示例:
四、实际场景中的选择
补充
1. 字典的键要求
2. 集合的元素要求
可变 vs 不可变 数据类型
可变对象的特点和适用场景
不可变对象的特点和适用场景

Python 数据类型详解:可变与不可变、可哈希与不可哈希

在Python中,理解数据类型的可变性可哈希性是编写高效代码的基础。本文将详细讨论Python中不同类型对象的可变性和哈希性,包括它们的优缺点和适用场景,帮助开发者更好地选择合适的数据类型。


一、数据类型分类表

数据类型可变性哈希性优点缺点适用场景示例
int不可变可哈希简单、可哈希修改需新建对象存储数值x = 5
float不可变可哈希精确度高、可哈希修改需新建对象科学计算x = 3.14
str不可变可哈希安全、可哈希修改需新建对象文本处理s = "hello"
tuple不可变可哈希安全、可哈希修改需新建对象多线程共享数据t = (1, 2, 3)
list可变不可哈希灵活、支持修改线程不安全动态数组lst = [1, 2, 3]
dict可变不可哈希快速查找、键值对存储不能作为字典键快速存储、查找d = {"a": 1}
set可变不可哈希支持去重、集合运算无法嵌套去重操作、集合运算s = {1, 2, 3}
frozenset不可变可哈希安全、可哈希不能修改不变集合fs = frozenset([1, 2, 3])

可变与不可变

可变不可变
listint
dictfloat
setbool
bytearraystr
collections.dequetuple
自定义对象frozenset

可哈希与不可哈希

可哈希不可哈希
intlist
floatdict
strset
tuplebytearray
frozensetcollections.deque
bytes

以下是关于可变与不可变数据类型的优缺点说明:

可变与不可变

可变对象

  • 优点
    • 高效内存使用:可在原地修改,避免创建新对象,节省内存和计算开销。
    • 灵活性强:适合需要频繁修改的场景,如动态数组、队列、缓存等。
  • 缺点
    • 线程不安全:在多线程环境中,多个线程同时修改可变对象可能导致数据竞争和不一致。
    • 数据一致性风险:函数传递可变对象时,内部修改会影响外部变量,可能导致意外错误。

不可变对象

  • 优点

    • 线程安全:由于不可变对象的内容无法修改,天然适合多线程环境,减少了数据竞争的风险。
    • 哈希性:大多数不可变对象是可哈希的,可以作为字典的键或集合的元素,支持快速查找。
  • 缺点

    • 修改效率低:每次修改都要创建新对象,频繁修改会导致性能下降。
    • 灵活性较差:不可变对象无法直接修改,适应性不如可变对象。

可哈希与不可哈希

可哈希对象

  • 优点

    • 可用于字典键:可哈希对象可以作为字典的键或集合的元素,支持高效的查找和插入。
    • 高效查找:哈希表依赖哈希值实现快速访问,平均时间复杂度为O(1)。
  • 缺点

    • 不能修改:为了保证哈希值不变,可哈希对象通常是不可变的,因此无法动态调整内容。
    • 哈希冲突问题:不同对象可能生成相同哈希值,需要良好的哈希算法来减少冲突。

不可哈希对象

  • 优点

    • 灵活修改:不可哈希对象可以随意修改内容,适合动态变化的数据结构。
    • 数据结构丰富:支持更多的操作方法,如增删改查操作。
  • 缺点

    • 不能用于字典键或集合元素:由于哈希值可能随内容变化而改变,无法用于字典或集合。
    • 查找效率较低:在需要频繁查找、插入和删除的场景下,不可哈希对象的效率通常较低。

二、可变与不可变对象

2.1 可变对象

可变对象指可以在内存中原地修改其内容的对象。Python中的listdictset等都是常见的可变对象。

优点:
  1. 内存高效:原地修改,无需新建对象。
  2. 灵活性:适合频繁修改的数据结构。
缺点:
  1. 线程不安全:多线程环境下容易产生数据竞争。
  2. 易出bug:传递可变对象时,内部修改会影响外部引用。
适用场景:

适用于频繁修改的数据,如动态数组、缓存、队列等。

示例:
python
my_list = [1, 2, 3] # 创建一个包含三个元素的列表 my_list.append(4) # 在列表末尾添加一个元素 print(my_list) # 输出: [1, 2, 3, 4]

关键点:可变对象适合动态修改数据,但在多线程环境中需格外小心。

2.2 不可变对象

不可变对象一旦创建,内容不可更改。常见的不可变对象有intstrtuple等。

优点:
  1. 线程安全:不可变对象不易产生数据竞争问题。
  2. 可哈希:大多数不可变对象是可哈希的,适合用作字典键。
缺点:
  1. 修改效率低:每次修改都会创建新对象,内存和性能开销大。
  2. 灵活性差:不支持直接修改,适用于静态数据。
适用场景:

适用于不变的常量、配置信息或多线程共享数据。

示例:
python
my_tuple = (1, 2, 3) # 创建一个不可变的元组 new_tuple = my_tuple + (4,) # 创建新元组,增加一个元素 print(new_tuple) # 输出: (1, 2, 3, 4)

关键点:不可变对象在多线程环境中安全,但修改成本较高,适合保存常量或键值。


三、可哈希与不可哈希对象

3.1 可哈希对象

可哈希对象能通过hash()函数计算哈希值,并且哈希值在对象生命周期中保持不变。Python中不可变对象大多是可哈希的,如intstrtuple

优点:
  1. 支持字典键:可哈希对象可以作为字典键或集合元素,支持高效查找。
  2. 快速查找:哈希表的查找效率高,平均时间复杂度为O(1)。
缺点:
  1. 不支持修改:由于哈希值固定,可哈希对象通常不可变,不能直接修改内容。
  2. 哈希冲突:不同对象可能生成相同哈希值,哈希冲突需有效处理。
适用场景:

适用于字典、集合等需要高效查找的场景。

示例:
python
my_dict = {"name": "Alice", "age": 30} # 使用字符串作为字典键 print(my_dict["name"]) # 输出: Alice

关键点:可哈希对象适用于需要高效查找的场景,如字典键、集合元素。

3.2 不可哈希对象

不可哈希对象不能通过hash()函数计算哈希值,通常是可变的,如listdictset

优点:
  1. 灵活修改:可随时修改内容,适用于需要频繁变动的数据。
  2. 丰富操作:支持多种增删改查操作,易用性强。
缺点:
  1. 不能用于字典键或集合元素:哈希值会随内容变化,导致无法用于字典或集合。
  2. 查找效率较低:查找操作需要遍历整个对象,效率不如哈希表。
适用场景:

适合需要频繁修改的数据结构,但不适合用作字典键或集合元素。

示例:
python
my_list = [1, 2, 3] # 创建一个可变的列表 my_list.append(4) # 修改列表,添加元素 print(my_list) # 输出: [1, 2, 3, 4]

关键点:不可哈希对象适合动态修改数据,但不能用作字典键。


四、实际场景中的选择

在不同场景中,根据数据的可变性和哈希性,选择合适的数据类型:

  1. 字典键选择:选择strtuple等可哈希的不可变类型作为字典键,确保查找效率。
  2. 多线程安全:在多线程环境中,尽量选择不可变对象,如tuple,避免数据竞争。
  3. 频繁修改数据:在需要动态修改数据的场景下,使用listdict等可变对象,以提高灵活性。

补充

数据类型可变性哈希性备注或使用场景
int不可变可哈希适合作为字典的键和集合中的元素。
float不可变可哈希浮点数在需要高精度时需谨慎。可用作字典键。
bool不可变可哈希通常用于条件判断,布尔值可用作字典键。
str不可变可哈希字符串广泛用于字典键和集合元素,常见且高效。
tuple不可变可哈希(元组内所有元素也必须可哈希)适合作为字典键,适用于多维数据的表达。
frozenset不可变可哈希不可变集合,可以作为字典键或其他集合的元素。
bytes不可变可哈希字节序列,常用于二进制数据处理,可作字典键。
list可变不可哈希动态数组,不能作为字典键或集合元素。
dict可变不可哈希存储键值对,键必须是可哈希的对象。
set可变不可哈希集合用于存储唯一值,不能用作字典键或集合中的元素。
bytearray可变不可哈希可变的字节序列,适合于处理二进制数据,不能作为字典键。
collections.deque可变不可哈希双端队列,适合需要快速从两端插入或删除元素的场景。
自定义对象取决于实现取决于实现如果需要自定义对象作为字典键,必须实现__hash__()__eq__()

1. 字典的键要求

字典的键必须是可哈希的对象。Python中,所有不可变对象默认是可哈希的,因此可以作为字典的键。常见的字典键包括:

  • intfloatstrtuple(且元组中的所有元素也必须是可哈希的)。

例如:

python
my_dict = { 1: "integer key", "key": "string key", (1, 2): "tuple key" }

但像listsetdict这样的可变对象,由于其不可哈希,不能用作字典的键:

python
my_dict = { [1, 2]: "this will raise an error" # TypeError: unhashable type: 'list' }

2. 集合的元素要求

集合的元素必须是可哈希的对象,类似于字典的键要求。常见可哈希类型如intfloatstrtuple等,可以作为集合的元素,而listset等可变对象不能作为集合元素。

例如:

python
my_set = {1, "hello", (1, 2), 3.14} # 合法 my_set = {[1, 2], "this will raise an error"} # TypeError: unhashable type: 'list'

可变 vs 不可变 数据类型

可变对象的特点和适用场景

  • 内存占用效率高:可变对象可以在原地修改,避免了创建新对象的开销。
  • 适合频繁修改的数据:如列表、字典、集合,适合频繁的插入、删除、修改操作。
  • 缺点:不能用于字典键或集合元素,线程不安全。

示例

python
# 可变对象 - 列表 my_list = [1, 2, 3] my_list.append(4) # 列表原地修改

不可变对象的特点和适用场景

  • 线程安全:不可变对象可以放心地在多线程环境下使用,不会发生竞争条件。
  • 适合用于字典键或集合元素:不可变对象因其哈希值不变,可以用于需要快速查找的场合。
  • 缺点:每次修改都会生成新对象,效率较低。

示例

python
# 不可变对象 - 元组 my_tuple = (1, 2, 3) new_tuple = my_tuple + (4,) # 创建新元组
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:GYC

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!