值在python中的任何地方都会发生变化

值在python中的任何地方都会发生变化,python,python-2.7,Python,Python 2.7,我无法理解为什么在start_state的board属性中也会发生更改,即使它是较早构建的。我肯定是在做傻事。python新手,来自C/C++背景,这种行为似乎很奇怪 如果要元组具有所有4个值,希望改变一元组的属性而不被复制到哪里,那么什么是工作? < P> Python,赋值与C++有很大的不同;事实上,变量的概念是不同的 在C++中,变量是一个存储地址,其中存储值,并与类型一起存储。您可以获取变量的引用甚至指针。赋值意味着将一个值从一个变量复制到另一个变量* 在Python中,值负责自己的

我无法理解为什么在start_state的board属性中也会发生更改,即使它是较早构建的。我肯定是在做傻事。python新手,来自C/C++背景,这种行为似乎很奇怪


如果要元组具有所有4个值,希望改变一元组的属性而不被复制到哪里,那么什么是工作?

< P> Python,赋值与C++有很大的不同;事实上,变量的概念是不同的

    在C++中,变量是一个存储地址,其中存储值,并与类型一起存储。您可以获取变量的引用甚至指针。赋值意味着将一个值从一个变量复制到另一个变量*
  • 在Python中,值负责自己的存储和类型;变量只是一个值的名称。一个值可以有任意数量的名称**
*……通常;您可以覆盖它,使其表示您想要的任何内容

**好的,任何正数。一旦它没有名字,它将被垃圾收集器清除


在简单的情况下,您可能知道这一点:

sz = input('Enter the size of the board: ')
board = [[0 for j in xrange(sz)] for i in xrange(sz)]

for row in range(sz):
    for col in range(sz):
        board[row][col] = input()

pqval = 1
steps = 2
start_state = sz , board , pqval ,steps

t=1
for row in range(sz):
    for col in range(sz):
        board[row][col] = t
        t=t+1
board[sz-1][sz-1] = 0
end_state = sz, board , pqval ,steps

print "Here is the starting position: "
print start_state

print "Here is the ending position: "
print end_state
但在任何情况下都是如此。因此,当您这样做时:

>>> a = [0]
>>> b = a
>>> b[0]
0
>>> a[0] = 1
>>> b[0]
1
…这只是意味着
start\u state[1]
将成为同一
board
对象的另一个名称。
start\u state[1]
是一个“复杂目标”,而不是一个普通变量,这一事实并不重要;您通过分配给
start\u state
而不是直接分配给
start\u state[1]
来间接创建它的事实并不重要;它仍然是一个名字

当然,对于
sz
pqval
steps
也是如此,但是你永远不会改变这些值,因为你不能;字符串和数字不能变异

重新分配
pqval
不会将
1
变成不同的数字;*它只是将
pqval
作为不同号码的名称,而将
start\u state[2]
保留为原始号码的名称。同样,重新分配
线路板
也不会影响
启动状态[1]
。只有在适当的位置突变
板才能做到这一点

*如果你能做到这一点,那将是一个地狱般的超级大国,但它的任何使用都可能打破宇宙

<>这可能会有点棘手,当你使用像<代码> += 之类的操作符时,尤其是如果你习惯C++的话。在C++中, += 总是意味着对变量进行变异,不管它是否意味着突变一个值;当你不能改变一个变量时,
+=
就是不起作用。在Python中,没有“变异变量”之类的东西;它总是意味着重新分配一个变量,不管它是否意味着改变一个值;当你不能改变一个值时,
+=
只需要重新分配一个新值


如果你想复制,你必须明确地去做。例如,其中任何一项都会起作用:

start_state = sz , board , pqval ,steps

或者,你也可以让
board
以与其他对象相同的方式工作,永远不会改变它,只会将它重新分配给新列表。例如,与此相反:

start_state = sz, board[:], pqval, steps
start_state = sz, copy.copy(board), pqval, steps
start_state = copy.deepcopy((sz, board, pqval, steps))
…你可以做:

    board[row][col] = t
当然这有点傻,但通常你可以将循环重写为一个列表,生成一个新的列表,这并不傻。例如:

    board = [[val if i, j != row, col else t for j, val in enumerate(row)]
             for i, row in enumerate(board)]

不幸的是,此时堆栈片段仅适用于JavaScript(+HTML+CSS);只需使用Python的常规代码块。(我为您编辑了这篇文章。)是我所知道的关于Python中名称实际工作原理的最好解释之一。@chthonicdaemon:同意。有几次,我写了一篇博文来解释一些简单但难以解释的事情,结果发现Ned Batcheld在前一周写了一个更简单更好的解释。上一次出现这种情况时,我很聪明,先检查一下,当然内德写得比我可能写得好得多,我只是把人指给他们看,节省了我的时间。谢谢你提醒我;那是属于我的书签。这总是真的吗?因为当我在ipythonshell中尝试以下操作时:t=1;p=(1,t);t++;打印页。它显示的是(1,1)而不是(1,2)@AnuragSharma:是的,它总是正确的。
t++
不是有效的Python,但是如果你的意思是
t+=1
,那么区别在于
t
引用一个不可变的
int
对象,因此
t+=1
使名称
t
引用一个新值,与更改
t
引用的
int
对象相反。@AnuragSharma:chepner是100%正确的。但我发现这样想更容易:
p[1]
不是对
t
的引用,它引用的值与
t
引用的值相同。因此,将
t
变成对其他事物的引用根本不会影响
p[1]
。我试图编辑答案,以便更清楚地解释这一点。
board = [[i*sz+j for j in range(sz)] for i in range(sz)]