Python 列表与数组 - 何时使用?
Posted
技术标签:
【中文标题】Python 列表与数组 - 何时使用?【英文标题】:Python List vs. Array - when to use? 【发布时间】:2010-09-15 14:47:44 【问题描述】:如果你正在创建一个一维数组,你可以将它实现为一个列表,或者使用标准库中的“数组”模块。我一直将列表用于一维数组。
我想改用数组模块的原因或情况是什么?
是为了性能和内存优化,还是我遗漏了一些明显的东西?
【问题讨论】:
【参考方案1】:基本上,Python 列表非常灵活,可以保存完全异构的任意数据,并且可以非常有效地附加到 amortized constant time 中。如果您需要高效且轻松地缩小和增加列表,那么它们就是您的最佳选择。但是它们使用比 C 数组更多的空间,部分原因是列表中的每个项目都需要构造一个单独的 Python 对象,即使对于可以用简单 C 类型表示的数据(例如 @987654324 @ 或 uint64_t
)。
另一方面,array.array
类型只是 C 数组的一个薄包装器。它只能保存同质数据(也就是说,所有相同类型的数据),因此它只使用sizeof(one object) * length
字节的内存。大多数情况下,您应该在需要将 C 数组公开给扩展或系统调用(例如,ioctl
或 fctnl
)时使用它。
array.array
也是在 Python 2.x (array('B', bytes)
) 中表示 可变 字符串的合理方式。然而,Python 2.6+ 和 3.x 提供了一个可变的 byte 字符串作为bytearray
。
但是,如果您想对同构的数值数据数组进行数学运算,那么最好使用 NumPy,它可以自动对复杂的多维数组进行矢量化操作。 p>
长话短说:array.array
在您出于数学以外的原因需要同构 C 数据数组时很有用。
【讨论】:
numpy.ndarray 的内存占用和array.array 一样吗? @Gordon,在大的连续数组的情况下应该非常相似:它们都需要sizeof(element)
×(元素数)字节,加上一个小的固定头用于开销。然而,ndarray 有一些处理不连续和稀疏数组的高级选项,我认为一些用于为大型数组分配内存的可插拔策略......其中一些高级功能将使其用户 less 内存,而其他人将通过使用更多内存来提高性能。
可以在固定时间内查找数组的第 i 个元素,而在链表中,在最坏的情况下它需要顺序 'n'。 python列表中第i个元素的查找时间是多少?
@NithishInpursuitOfhappiness,Python 列表不是链表。它在内部表示为一个数组,并且具有与 Java 的 ArrayList 相同的时间复杂度特征。因此,获取和设置 Python 列表的第 i 个元素需要恒定时间。将元素附加到 Python 列表需要 摊销常数时间,因为当空间不足时,数组大小会加倍。在 Python 列表的中间插入或删除元素需要 O(n) 时间,因为需要移动元素。参考见:wiki.python.org/moin/TimeComplexity
@Timo,这正是答案中的示例已经显示的内容。【参考方案2】:
对于几乎所有情况,普通列表都是正确的选择。 arrays 模块更像是 C 数组的薄包装器,它为您提供了一种强类型容器(请参阅docs),可以访问更多类似 C 的类型,例如有符号/无符号短或双精度,它们不属于内置类型。我会说只有当你真的需要它时才使用数组模块,在所有其他情况下坚持使用列表。
【讨论】:
可能,但从未真正使用过,但运行一些微基准测试会很有趣。 实际上,我做了一个快速测试——我对一个包含 100M 个条目的列表进行了计时,并使用相应的数组进行了相同的测试,该列表实际上快了大约 10%。 列表更快,因为对数组“原始”数据的操作需要在读取或写入数组时不断创建和销毁 python 对象。 @Moe,正如我在上面的回答中指出的那样,Python 的内置array
不适合做数学运算。如果您尝试使用 NumPy 的 ndarray
对 10^8 个数字的数组求和,它将完全将 list
吹走。 @tzot 对为什么内置 array
的数学运算速度很慢有正确的想法。
我刚刚测试过,numpy 在我的机器上快了 86.6 倍。【参考方案3】:
如果您不知道为什么要使用数组模块,您可能不需要它(请注意,我并不是要以居高临下的态度说)方式!)。大多数时候,数组模块用于与 C 代码接口。为了更直接地回答您关于性能的问题:
在某些用途上,数组比列表更有效。如果您需要分配一个您知道不会更改的数组,那么数组可以更快并且使用更少的内存。 GvR 有一个optimization anecdote,其中数组模块胜出(读了很久,但值得)。
另一方面,列表比数组占用更多内存的部分原因是,当所有分配的元素都被使用时,python 会分配一些额外的元素。这意味着将项目附加到列表更快。因此,如果您打算添加项目,列表是您的最佳选择。
TL;DR 如果您有特殊的优化需求或者您需要与 C 代码交互(并且不能使用 pyrex),我只会使用数组。
【讨论】:
+1 用于具体示例并提及速度优势。最重要的答案让我想知道,“有时间记忆权衡吗?”和“这不是一个非常深奥的低内存案例有什么用吗?” 你能解释一下“当所有分配的元素都被使用时分配一些额外的元素”。你所说的使用是什么意思,它会在哪里分配【参考方案4】:这是一个权衡!
各有优劣:
列表
灵活 可以是异构的数组(例如:numpy 数组)
统一值数组 同质 紧凑(大小) 高效(功能和速度) 方便【讨论】:
问题是python中的数组模块;不是 numpy 数组。除了尺寸效率之外,他们没有很多优点。它们并不快。【参考方案5】:我的理解是数组的存储效率更高(即作为连续的内存块与指向 Python 对象的指针),但我不知道有任何性能优势。此外,对于数组,您必须存储相同类型的基元,而列表可以存储任何内容。
【讨论】:
【参考方案6】:标准库数组对于二进制 I/O 很有用,例如将整数列表转换为字符串以写入波形文件。也就是说,正如许多人已经指出的那样,如果您要进行任何实际工作,那么您应该考虑使用 NumPy。
【讨论】:
【参考方案7】:如果您要使用数组,请考虑使用 numpy 或 scipy 包,它们为数组提供了更大的灵活性。
【讨论】:
【参考方案8】:数组只能用于特定类型,而列表可以用于任何对象。
数组也只能是一种类型的数据,而列表可以有各种对象类型的条目。
数组对于一些数值计算也更有效。
【讨论】:
内置 python 数组在性能方面效率不高,仅在内存方面。 存在数组在处理方面更高效的实例。请参阅下面的帖子:***.com/questions/176011/…【参考方案9】:这个答案将总结几乎所有关于何时使用 List 和 Array 的查询:
这两种数据类型的主要区别在于您可以对它们执行的操作。例如,您可以将一个数组除以 3,它会将数组的每个元素除以 3。列表不能这样做。
列表是python语法的一部分,所以不需要声明它,而你必须在使用它之前声明数组。
您可以将不同数据类型的值存储在列表中(异构),而在 Array 中您只能存储相同数据类型的值(同类)。
与列表相比,数组功能丰富且速度快,广泛用于算术运算和存储大量数据。
与列表相比,数组占用的内存更少。
【讨论】:
【参考方案10】:关于性能,这里有一些比较 python 列表、数组和 numpy 数组的数字(所有这些都在 2017 Macbook Pro 上使用 Python 3.7)。 最终结果是 python 列表对于这些操作是最快的。
# Python list with append()
np.mean(timeit.repeat(setup="a = []", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.054 +/- 0.025 msec
# Python array with append()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.append(1.0)", number=1000, repeat=5000)) * 1000
# 0.104 +/- 0.025 msec
# Numpy array with append()
np.mean(timeit.repeat(setup="import numpy as np; a = np.array([])", stmt="np.append(a, [1.0])", number=1000, repeat=5000)) * 1000
# 5.183 +/- 0.950 msec
# Python list using +=
np.mean(timeit.repeat(setup="a = []", stmt="a += [1.0]", number=1000, repeat=5000)) * 1000
# 0.062 +/- 0.021 msec
# Python array using +=
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a += array.array('f', [1.0]) ", number=1000, repeat=5000)) * 1000
# 0.289 +/- 0.043 msec
# Python list using extend()
np.mean(timeit.repeat(setup="a = []", stmt="a.extend([1.0])", number=1000, repeat=5000)) * 1000
# 0.083 +/- 0.020 msec
# Python array using extend()
np.mean(timeit.repeat(setup="import array; a = array.array('f')", stmt="a.extend([1.0]) ", number=1000, repeat=5000)) * 1000
# 0.169 +/- 0.034
【讨论】:
【参考方案11】:numpy 数组和列表的一个重要区别是数组切片是原始数组的视图。这意味着数据不会被复制,对视图的任何修改都会反映在源数组中。
【讨论】:
以上是关于Python 列表与数组 - 何时使用?的主要内容,如果未能解决你的问题,请参考以下文章
在Python中,何时使用Dictionary,List或Set?