我似乎无法在任何地方找到解释......
假设我有一个向量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的了解,这是错误的,我相信当我开始使用数千或数百万个值的向量时它会很慢。
我还能做什么?
答案 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
中的每个元素。
如果元素是不可变对象,如str
,int
,float
或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
,一切都应该是好的。