假设我有一个我希望增加的数字列表,我只对递增的值感兴趣,而不是之后的原始值。最简单的方法是原位,不复制列表?
确实
a = [1, 2, 3]
a = [i+1 for i in a]
导致a
的中间副本,或者python解释器是否优化了这个?
不幸的是,我的python知识仍然是肤浅的。我的母语是C ++。
答案 0 :(得分:4)
如果不复制列表,您可以执行此操作:
In [1]: a = [1, 2, 3]
In [2]: id(a)
Out[2]: 48701592
In [3]: for i in xrange(len(a)): # range(len(a)) for python 3
...: a[i] += 1
...:
In [4]: a
Out[4]: [2, 3, 4]
In [5]: id(a)
Out[5]: 48701592
答案 1 :(得分:3)
列表中的整数有一个问题:这些实际上是不可变对象,所以如果你增加一个整数,它实际上会被一个新对象重新调整。
因此,虽然列表解析将创建一个中间副本,但开销可能不是那么大的问题。如果有疑问,您可以使用timeit来分析备选方案。
如果列表中还有其他引用,则会出现一个经常被忽视的问题:
>>> a = [1,2,3,4]
>>> b = a
>>> for i in xrange(len(a)): # range() in Python 3!!
... a[i] += 1
...
>>> a
[2, 3, 4, 5]
>>> b
[2, 3, 4, 5]
如果为a创建新列表,b当然不会看到这些修改:
>>> a = [1,2,3,4]
>>> b = a
>>> a = [i + 1 for i in a]
>>> a
[2, 3, 4, 5]
>>> b
[1, 2, 3, 4]
所以,答案实际上是:它取决于。使用for循环
答案 2 :(得分:2)
使用numpy数组的另一个选项
import numpy as np
A=np.array([1,2,3])
A=A+1
答案 3 :(得分:0)
我相信(但我是错误 - 请参阅注释),避免复制列表的正确方法是使用切片赋值和生成器表达式:
Actions act = new Actions(driver);
WebElement onElement = driver.findElement(By.linkText("Gmail"));
act.contextClick(onElement).perform();
act.sendKeys("w").perform();
使用列表推导a[:] = (i+1 for i in a)
的问题在于它将首先构建一个新列表,然后切片赋值将遍历临时列表以将[i+1 for i in a]
的每个元素绑定到该值。
使用生成器表达式,当切片分配请求其他值时,懒惰地遍历现有列表,因此原则上不需要创建临时列表。但是 - 正如我更正的那样 - 切片分配会导致从生成器表达式创建列表。
答案 4 :(得分:-1)
Ans to Q#1
- 一旦我们进一步操作数组(或数组元素),它就像对原始数组的引用,并对其进行持久的新更改。它可以被称为intermediate
副本,但显然不是原始数组的副本。
Ans to Q#2
- Python内部不会优化a
,如问题中所述。
虽然您可以通过以下方式获得所需的结果:
a = [1, 2, 3]
a = [i+1 for i in a]
print a
仍然使用 slicing
符号 :
非常合适:
a[:] = [i+1 for i in a]
print a
***感谢@Paul Rooney分享这个例子。
答案 5 :(得分:-2)
要增加列表中的每个元素而不创建列表的另一个副本,您应该按照@ Akavall的回答。
如果列表理解创建了列表的中间副本,请回答您的问题,以下是解释。
列表理解
a = [i+1 for i in a]
可以扩展为:
b = []
for i in a:
b.append(i+1)
a = b
如您所见,我们遍历列表并逐个递增每个元素。这些元素存储在临时列表中,新列表将分配回a
。
在这种情况下,a
只是引用列表的标签。 a = b
只是更新引用以指向新列表。