Python - 一个变量等于另一个变量,它不应该

时间:2008-11-05 07:54:08

标签: python variables

这是我的示例代码。它是高斯塞德尔(矩阵求解器)的迭代过程。基本上当错误足够小时,它就会突破while循环。

i=1
while (i>0):
    x_past = x_present

    j=0
    while(j<3):
        value=0
        k=0
        while(k<3):
            if(k!=j):
                if(i==1):
                    if(k>j):
                        value=value+0
                    else:
                        value=value+x_present[k]*eqn[j][k]    
                else:
                    value=value+x_present[k]*eqn[j][k]
            else:
                value=value+eqn[j][k]
            k=k+1
        x_present[j:j+1]=[value]
        j=j+1
    print "X_PAST"
    print x_past
    print "X_PRESENT"
    print x_present    
    if(error(x_past, x_present)<10**-2):
        break;
    i=i+1

我减少了代码,因此更易于管理。如果你不明白它的作用对解决这个问题不是那么重要。

这是问题所在。每次

x_present[j:j+1]=[value]

运行,x_past等于x_present。我不知道为什么会这样,因为我设置的x_past等于x_present的唯一位置是在循环的顶部。如果我带走了

x_past=x_present

句子,x_past永远不会等于x_present。这使我认为这是导致问题的两个陈述的某种组合。

如果每次x_past = x_present错误= 0并且第一次迭代后循环中断,则这是一个很大的问题。代码确实有效,例如,如果我告诉代码运行8次迭代并且中断它给了我应该的答案。

我一直试图在过去的4个小时内解决这个问题并且完全被困住了。我没有使用python很长时间,所以我的麻烦射击技巧语法明智不是那么好。任何帮助将不胜感激!!

6 个答案:

答案 0 :(得分:30)

是的,我认为这里的答案显示了您的问题。 只是试着澄清一下。

您正在引用列表,因此当列表更改时,对该列表的任何引用都将反映该更改。为了证明:

>>> x_present = [4,5,6]
>>>
>>> x_past = x_present
>>>
>>> x_past
[4, 5, 6]
>>>
>>> x_present.append(7)
>>>
>>> x_past
[4, 5, 6, 7]
>>>

如果您需要列表的副本,则必须执行此操作, listcopy = mylist [:]

>>> x_past = x_present[:]
>>> x_past
[4, 5, 6, 7]
>>>
>>> x_present.append(8)
>>>
>>> x_past
[4, 5, 6, 7]

答案 1 :(得分:4)

什么是x_past和x_present?我不太了解Python,但是从.NET / Java的角度来看,如果它们引用了某些数据结构(地图或其他),那么让它们引用同一个对象(就像你在开始时那样)将意味着通过一个变量进行的任何更改都将通过另一个变量可见。听起来您需要获取数据结构的副本而不是仅仅执行引用分配。您正在使用的数据结构是否具有任何类型的“克隆”功能?

正如我所说,我不太了解Python,所以这可能是完全错误的......

答案 2 :(得分:3)

正如其他人所指出的那样,答案是将x_past = x_present替换为x_past = x_present[:]。通常,您可以使用copy模块在​​Python中复制对象。

>>> import copy
>>> a = range(10)
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b = a
>>> a += 10, 11
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> c = copy.copy(a) # shallow copy
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
>>> del a[3:]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

至少可以说你的代码是单声道的。

可以用以下代码替换它:

import copy
# assert(len(x_present) >= len(eqn))

first = True
while True:
    x_past = copy.copy(x_present) # copy

    for j, eqj in enumerate(eqn):
        x_present[j] = sum(x_present[k] * eqj[k] 
                           for k in range(j if first else len(eqj)) 
                           if k != j)
        x_present[j] += eqj[j] 

    print "X_PAST\n%s\nX_PRESENT\n%s" % (x_past, x_present)
    if allequal(x_past, x_present, tolerance=10**-2):
        break
    first = False

以下是allequal()的定义(使用绝对错误。在您的情况下可能会或可能不是一个好主意(您可以使用相对错误)):

def allequal(x, y, tolerance):
    return (len(x) == len(y) and 
            all(-tolerance < (xx - yy) < tolerance
                for xx, yy in zip(x, y)))

答案 3 :(得分:1)

在Python中,一切都是对象。 所以语句x_past = x_present指向相同的引用。

答案 4 :(得分:0)

看起来x_present是一个列表。我怀疑这意味着赋值x_last = x_present使x_last成为别名,即它们引用相同的变量。情况可能会这样吗?

答案 5 :(得分:0)

尝试将x_past = x_present行更改为x_past = [x for x in x_present]并查看是否有帮助。

列表复制速记是我最喜欢的python功能,因为我可以使用其他语言无法实现的单行:

greaterthan100 = [x for x in number if x > 100]

notinblacklist = [x for x in mylist if x not in blacklist]

firstchildofbigfamily = [x.child[0] for x in familylist if len(x.child) > 10]