为什么Python中的元素...... in ...:语句使用byValue行为?

时间:2010-11-17 17:20:00

标签: python numpy iteration

我似乎无法在任何地方找到解释......

假设我有一个向量y初始化为全零:

from numpy import *
y = zeros(5)

它也可能是一个简单的python数组,我认为它不重要。

我注意到for x in y:语句的行为是它在y中对每个元素进行复制,因此当你修改x时,它不会修改y。

for x in y:
    x = 1
print y

output : array([ 0.,  0.,  0.,  0.,  0.])

我的问题如下:为什么会这样?我在Python中认为一切都是byReference,并且很少有byValue传遍?

如何使用引用变量执行以下操作?执行以下操作似乎有效:

for i in range(len(y)):
    y[i] = 2*rand()-1

但是根据我对Python的了解,这是错误的,我相信当我开始使用数千或数百万个值的向量时它会很慢。

我还能做什么?

4 个答案:

答案 0 :(得分:8)

你可以替换它:

y = np.zeros(5)
for i in range(len(y)):
    y[i] = 2*rand()-1

使用:

y=2*np.random.rand(5)-1

如果y是Python序列(元组,列表,数组等)或Numpy数组,

for x in y:

遍历y,将x设置为y中的每个元素。 如果元素是不可变对象,如strintfloat或Numpy数字类型, 然后更改x的值不会更改y中的值。

如果元素是可变对象,例如list,则变异list会影响y

以这种方式思考:x“指向”一个对象:

y---> [o----o----o----o]
            ^
            |
            x

编写作业声明时:

x += 1

现在您将x重新分配给“指向”另一个对象:

y---> [o----o----o----o]

x---> o

另一方面,如果你使用x.append(1)改变列表,那么 x仍指向同一个对象(例如列表),但您已经改变了该列表的内容。

答案 1 :(得分:4)

Python 仅使用“引用”。但是Python中的所谓“引用”(和Java,以及其他少数几种语言)并不像“引用传递”或“C ++中的引用”。当您迭代for i in iterable:之类的内容时,i指向当前项。但是当您在循环中执行i = ...时,您将使用新的覆盖覆盖该引用,而不是替换指向的对象。实际上,Python(以及提到的所有其他语言)都是按值传递的。除了那些值总是(种类)指针。

请注意,这不适用于i.attr = ...!设置成员是不同的,它是一个方法调用(对象的.__setitem____dict__.__setattr__ afaik的.__setattribute__之一。因此,如果您在循环中执行了i.some_member,那么您确实会更改迭代的项目。还要注意,这当然没有数字或字符串等不可变对象 - 你不可能改变它们。

如果你想改变,例如直接列表,您需要使用索引(虽然您不需要range(len(...)),但您可以使用enumerate(the_list)并获得索引当前项目)。另外,请考虑使用例如首先生成所需的值。列表理解。

答案 2 :(得分:1)

如果我错了,请有人纠正我,但Python中的整数类型是不可变的,这就是为什么当你对向量的一个元素执行某些操作时,你会得到一个新对象。我看了看,但没有找到任何关于这种预感的确认,但是当我尝试

>>> def zeros(length):
...     vector = []
...     for each in range(length):
...         vector.append([0])
...     return vector
... 
>>> zeros(8)
[[0], [0], [0], [0], [0], [0], [0], [0]]
>>> y = zeros(8)
>>> for x in y:
...     x[0] += 1
... 
>>> y
[[1], [1], [1], [1], [1], [1], [1], [1]]

我们知道列表是可变的,我们得到了我们期望的结果。

答案 3 :(得分:0)

我根本看不到代码示例是如何错误的 - 只要y循环所在的范围可以访问for,一切都应该是好的。