在 Luciano Ramalho 所著的《Fluent Python》一书(第 2 版)中,他定义了容器序列和平面序列的概念:
容器序列保存对其所包含的对象的引用,这些对象可以是任何类型,而平面序列将其内容的值存储在其自己的内存空间中,而不是作为不同的 Python 对象。
range
我们可以说和类型的对象bytearray
是平面序列吗(我认为这些对象不能包含引用,但不确定)?
有没有一种简单的方法来测试一个序列是否是平面的?
我刚刚发现这篇文章引用了《Fluent Python》一书第一版中的一段话(我个人只有第二版):
平面序列:
str
,bytes
,bytearray
,memoryview
和array.array
仅保存一种类型的项目。
因此,这似乎bytearray
是一个平序列。在第二版(第 22 页)中,作者只说
扁平序列 – 保存一种简单类型的项目。例如:
str
、bytes
和array.array
。
容器序列 – 可以保存不同类型的项目,包括嵌套容器。例如:list
、tuple
和collections.deque
。
您说的对
bytearray
。它引用内部可变内存空间来保存仅一种简单类型(字节)的对象,因此根据作者的定义,它是一个平面序列。不过,对象
range
有点棘手。我想说它不符合作者给出的任何一个标准,尽管它肯定是一个序列。但是,它不包含任何值,而只是存储构造它的和参数start
,并在需要时动态计算它应该包含哪些值。在此之前,它不会引用它们,无论是作为 Python 对象还是其他。这意味着您可以在恒定时间内创建任意大小的 ,因为只需要分配几个整数。stop
step
range
最后说明一下:“平面序列”和“容器序列”的定义在 Python 开发社区中并不广泛使用。它们可能在您的书中有用,可以解释容器行为的一些差异,但更广泛的 Python 程序员不会理解它们。一般来说,给定容器如何存储其内容的细节通常不是您需要关心的事情。不指定实现细节通常是 Python 设计团队的故意选择,这样如果有更高效的实现可用,代码就可以切换到它。不久前 Python 的字典就发生了这种情况,由于实现更改的副作用,字典变得有序(按插入顺序)。由于许多以前的实现细节未指定,因此没有中断向后兼容性,因为所有记录的接口仍然以相同的方式工作。
range
根本不是容器序列。它除了原始参数和当前位置外不存储任何内容,并根据需要动态生成值。您可以像序列一样对其进行索引,但它实际上会计算值(r[i] == r.start + i*r.step
如果小于r.stop
)。扁平序列的示例包括字符串、字节数组和 numpy 数组。但是,这些数组的存储方式是实现细节。从技术上讲,没有任何规定禁止它们使用对对象的引用,只是这样做效率非常低,无论是在存储空间方面,还是在使用它们的函数的实现方面。