Python Slice Assignment Memory Usage
我在这里读到一条关于栈溢出的注释,在改变列表时执行切片分配更节省内存。例如,
1 | a[:] = [i + 6 for i in a] |
应该比
1 | a = [i + 6 for i in a] |
号
因为前者替换了现有列表中的元素,而后者创建了一个新列表并将
1 2 3 4 | $ python -mtimeit -s 'a = [1, 2, 3]' 'a[:] = [i + 6 for i in a]' 1000000 loops, best of 3: 1.53 usec per loop $ python -mtimeit -s 'a = [1, 2, 3]' 'a = [i + 6 for i in a]' 1000000 loops, best of 3: 1.37 usec per loop |
这就是我所期望的,因为重新绑定变量应该比替换列表中的元素更快。但是,我找不到任何支持内存使用声明的官方文档,我不确定如何对其进行基准测试。
从表面上看,记忆使用声明对我来说是有意义的。但是,如果再考虑一下,我希望在前面的方法中,解释器将从列表理解中创建一个新的列表,然后将该列表中的值复制到
是否有人能明确地(通过基准测试或官方文档)显示这两种方法中哪一种更节省内存/哪一种是首选方法?
事先谢谢。
这条线
1 | a[:] = [i + 6 for i in a] |
不会保存任何内存。如语言文档中所述,python首先评估右侧:
An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.
号
在目前的情况下,单个结果对象将是一个新的列表,目标列表中的单个目标将是
我们可以用生成器表达式替换列表理解:
1 | a[:] = (i + 6 for i in a) |
号
现在,右侧的计算结果是生成器而不是列表。基准测试表明,这仍然比幼稚的
1 | a = [i + 6 for i in a] |
那么生成器表达式是否实际保存了任何内存?乍一看,你可能会认为是这样。但是深入研究函数
1 | v_as_SF = PySequence_Fast(v,"can only assign an iterable"); |
。
使用pysequence_fast()首先将iterable(在本例中是生成器)转换为元组,然后将其复制到旧列表中。元组使用与列表相同的内存量,因此使用生成器表达式与在本例中使用列表理解基本相同。在最后一次复制期间,原始列表中的项目将被重用。
从道义上看,最简单的方法在任何方面都是最好的。