我想从第 k 个元素 IN PLACE 中反转一个列表,这是我的代码:
list[:] = list[len(list) - k:] + list[:len(list) - k]
我知道这是正确的代码,而以下代码不正确。有谁知道为什么?
list = list[len(list) - k:] + list[:len(list) - k]
谢谢!
我想从第 k 个元素 IN PLACE 中反转一个列表,这是我的代码:
list[:] = list[len(list) - k:] + list[:len(list) - k]
我知道这是正确的代码,而以下代码不正确。有谁知道为什么?
list = list[len(list) - k:] + list[:len(list) - k]
谢谢!
区别在于python 语言参考中指定的赋值语法的反映。您的第一个示例生成列表的修改副本并将列表的内容设置为副本的内容。第二个示例生成修改后的副本并分配list
标识符以指向该副本。
id
通过在之前和之后调用您的列表,您可以更清楚地看到这一点:
id(list)
list[:] = list[len(list) - k:] + list[:len(list) - k]
id(list) # prints the same id as above
id(list)
list = list[len(list) - k:] + list[:len(list) - k]
id(list) # prints a new id representing a new list object
在第二种情况下,list
具有不同的 id,因为它实际上表示一个新的列表对象,其中第一种重用list
并且仅更新内容。
话虽如此,请注意在这两种情况下都在制作列表的副本,因此您并没有真正获得任何东西。这两个更新都没有真正就地计算。出于这个原因,在 99% 的情况下,我会使用第二种更简洁的语法。
此外,“就地”版本涉及更新列表中可能的许多元素,其中仅更新list
标识符始终是一次更新。通过以下实验,您可以看到额外复制工作带来的少量性能开销:
$ python -m timeit 'x=range(100000); x[:]=x[::-1]'
100 loops, best of 3: 3.62 msec per loop
$ python -m timeit 'x=range(100000); x=x[::-1]'
100 loops, best of 3: 2.62 msec per loop
$ python -m timeit 'x=range(10); x[:]=x[5:] + x[:5]'
1000000 loops, best of 3: 1.31 usec per loop
$ python -m timeit 'x=range(10); x=x[5:] + x[:5]'
1000000 loops, best of 3: 1.02 usec per loop