Python中元组、列表和字典的存储方式
在Python中,元组、列表和字典是怎么存储的呢?
首先,元组(tuple)是一种不可变的数据结构,这意味着一旦你创建了一个元组,就不能再改变它里面的内容。这是因为元组在内存中是以一种特殊的方式存储的,设计上就是为了保持数据的稳定性和安全性。想象一下,元组就像一个装满了固定物品的箱子,你不能随便把里面的东西拿出来或换掉。
而列表(list)则是可变的,你可以随时添加、删除或修改里面的元素。列表就像一个可以随意调整的书架,你可以随时把书拿出来或者放进去。
至于字典(dictionary),它是一种以键值对形式存储数据的结构。你可以把字典想象成一个带标签的文件夹,每个标签(键)都指向一个具体的内容(值)。字典也可以随意修改,你可以添加新的标签或者改变已有标签指向的内容。
总的来说,元组、列表和字典在内存中的存储方式不同,导致了它们在使用上的不同特点。元组的不可变性让它在某些情况下更加安全,而列表和字典的灵活性则让它们在处理数据时更加方便。
1 个回答
在后端,不同的Python实现对数据的存储方式是不同的。
不过,数据是怎么存储的,几乎和你不能改变元组没有关系。你不能改变元组是因为它们被设计成不可变的。元组没有实现 __setitem__
方法或者 append
方法。用ABC(抽象基类)的术语来说(这通常是你最关心的,而不是底层的实现),元组只实现了 Sequence
,而没有实现 MutableSequence
。在大多数实现中,元组和列表的底层结构差不多,只是元组可能不知道怎么扩展;它们的主要区别在于没有实现可以改变内容的方法。
在CPython中:
元组和列表都有一个小的头部和一个指向连续数组的指针,这个数组里存的是指向 PyObject
的指针。如果你在列表已经满了的时候再添加元素,它会分配一个新的、更大的数组,把现有的指针复制过去,然后删除旧的数组。
字典则有一个小的头部和一个指向哈希表的指针,哈希表中的每个桶里都有一个哈希值、一个键和一个值(键和值都是指向 PyObject
的指针)。
这些细节在C API中有文档说明,具体可以查看 Concrete Objects Layer。源代码在 Objects 目录下。(注意,在C API层面,你实际上可以调用 PyTuple_SetItem
,甚至 _PyTuple_Resize
,但如果任何Python代码可能看到这个元组,强烈不建议这样做。)
* 实际上,在最新版本中,哈希表可以分成两部分,这样多个字典可以共享相同的键。有关如何实现的细节,请查看 PEP 412 和 dictobject.c
中的评论。
在PyPy中,Python的列表、元组和字典对象实际上是用RPython(Python的一个子集)实现的,然后通过PyPy的魔法转换成C。元组和列表的实现基本上和你预期的一样,但字典有一些聪明的技巧,值得一读。*
* 它基本上把“分表”这个概念进一步发展了——更准确地说,CPython借用了PyPy的分表思路,但没有做得那么深入。
在Jython和IronPython中,元组和列表分别是用Java和C#实现的。记得早期版本的Jython直接使用Java的集合类型来实现Python的类型,但他们很久以前就停止了这种做法,代码更像CPython(只是基于Java数组,而不是C的指针)。它的实现和CPython 2.5-2.7时期的相似。我猜IronPython也是类似的,但我没有去查。
在我知道的两个部分Python在JavaScript中的实现中,这三种类型都是基于JS的 Object
实现的,但在字典的键处理上需要做一些复杂的操作。