如果我这样做:
x = 1
y = [x,x,x,x]
y[1] = 2
print y
我明白了:
[1,2,1,1]
但如果我这样做:
x = [1,1]
y = [x,x,x,x]
y[1][0] = 2
print y
我明白了:
[[2,1],[2,1],[2,1],[2,1]]
有人可以向我解释两者之间的细微差别吗?我的意思是,就像Python如何分配内存一样,在第一种情况下,y的四个元素读取不同的内存位置,但在第二种情况下,y的四个元素读取相同的位置?
为什么Python的行为如此?当我使用Matlab时,不会发生这样的事情。
谢谢。
答案 0 :(得分:6)
Python中的所有变量都包含引用(指针)。即使是直接存储在C等其他语言中的变量中的简单类型(如整数)也会使用Python中的引用进行存储。为名称指定值会更改名称所指的内容(指向)。准确理解何时发生这种情况对理解Python的行为方式至关重要。
让我们开始吧:
a = 2 # points a to the integer object 2
a = 3 # points a to a different integer object, 3
b = [1, 2, 3] # points b to a new list object [1, 2, 3]
下一步:
c = a # a and c now point to the same integer object, 3
d = b # b and d now point to the same list object, [1, 2, 3]
到目前为止这么好,对吗?现在你可以看到为什么它的工作方式如下:
d.append(4) # b and d still point to the same list object, which is
# now [1, 2, 3, 4]
print(b) # prints [1, 2, 3, 4] -- how could it not?
事实上,无论对象的类型如何,一切都以相同的方式工作。只是某些类型你不能“就地”改变它们中的数字,字符串和元组:
a += 2 # a now points to the integer object 5, because you can't
# change 2 into 5 (integers are immutable)
print(c) # prints 3. c still points to 3, because you never told
# Python to make c point anywhere else!
可是:
b.append(5) # doesn't change what b points to, just changes the list
b += [6] # also (somewhat counterintuitively) doesn't change what b
# points to, even though it did with integers
print(d) # prints [1, 2, 3, 4, 5, 6] because b and d still point to
# the same list
+=
的情况有点令人困惑,因为它与列表和整数的行为完全不同。但是,请记住,+=
(以及大多数其他Python操作)可以由对象本身重新定义。在这种情况下,+=
由附加到整数和列表类型的方法__iadd__()
处理。在整数上,+=
返回一个新对象,因为它必须是整数,它是不可变的。在列表中,+=
更有效地返回传递的相同对象,而不是复制。
总结一下:
+=
这样的增强赋值)实际上不是赋值,而是方法调用,并不一定会改变变量(名称)引用的对象(指向) ,虽然他们可以答案 1 :(得分:0)
在第一种情况下,x
只是integer
,而在第二种情况下,列出的是reference
。
第一种情况下的分配会将x
的内容复制到integer
列表中。在分配之后,对x所做的任何更改都不会反映在y
中,因为x
和y
的元素存储在不同的内存位置。
但在第二种情况下,赋值y=[x,x,x,x]
存储了4个相同列表[1,1]
的引用。由于每个引用都指向相同的内存位置,因此更改其中任何一个或甚至更改原始x
都会在任何地方反映相同的更改。
答案 2 :(得分:0)
问题在于,在第一个示例中,您正在更改y
的内容,而在第二个示例中,您正在更改y
内的列表内容
试试这个:
x = 1
y = [x,x,x,x]
print map(id,y)
x = [1,1]
y = [x,x,x,x]
print map(id,y)
输出(会有所不同):
[41548904, 41548904, 41548904, 41548904]
[50255344, 50255344, 50255344, 50255344]
请注意,两个列表都有相同对象的4倍,现在尝试:
x = 1
y = [x,x,x,x]
y[1] = 2
print map(id,y)
x = [1,1]
y = [x,x,x,x]
y[1] = [2,1]
print map(id,y)
输出(会有所不同):
[28224616, 28224592, 28224616, 28224616]
[36931056, 36929264, 36931056, 36931056]
请注意,您已在两个示例中更改了列表y
的元素。
最后,如果你这样做:
x = [1,1]
y = [x,x,x,x]
y[1][0] = 2
您正在更改位置1
上x元素的内容(与所有其他位置一样),因此当您打印y
时,您将打印x
四次第一个值改变了。