2016-03-26 36 views
0

我使用下面的程序返回修改:變量修改的功能,當它不應該

def coordsRelToPoint(origin,point): 

    result = (int(origin[0]) - int(point[0]) , int(origin[1]) - int(point[1])) 

    return result 

def initCoordsRelToStartBattle(calibration): 
    print ('FUNCTION BEGIN') 
    print ('orig: %s' % str(calibration['center'])) 
    print ('') 
    new_calibration = {} 
    new_calibration = calibration 

    print ('orig: %s' % str(calibration['center'])) 
    print ('') 

    new_calibration['center'] = coordsRelToPoint((774,454),calibration['center']) 

    print ('orig: %s' % str(calibration['center'])) 
    print ('') 
    print ('new: %s' % str(new_calibration['center'])) 
    print ('') 
    print ('FUNCTION END')   
    return new_calibration 

def main(): 
    calibration = {} 
    calibration['center'] = (156,20) 
    initCoordsRelToStartBattle(calibration) 

if __name__ == "__main__": 
    main() 

它打印屏幕上的以下內容:

FUNCTION BEGIN 
orig: (156, 20) 

orig: (156, 20) 

orig: (618, 434) 

new: (618, 434) 

FUNCTION END 

我不明白這就是爲什麼我的原始變量在調用函數時被修改,因爲它在另一個函數中被使用。

我不應該看到行的原點:(618,434),因爲這意味着我的變量校準已被修改,即使它沒有從函數返回。

回答

0

問題是,當您將現有字典分配給新變量時,實際上新變量指向同一個對象。您可以使用id函數基本檢查對象的地址。在這個例子中,id(calibration)id(new_calibration),你會看到他們有相同的地址。這就是爲什麼如果修改新字典也會修改原始字典的原因。

爲了有實際的新副本,即可以使用copy包,並使用deepcopy函數。你應該改變線的new_calibration初始化,即:

new_calibration = copy.deepcopy(calibration) 

,這導致保留原始變量。

請注意,在問題的代碼中,淺拷貝也起作用,因爲tuple是字典的元素,它是不可變對象。淺拷貝和深拷貝之間的區別基本上是第一個創建一個新的複合對象,並且在可能的情況下添加複製對象中的引用,而後者遞歸地創建新的對象。在問題中,如果在字典中每個元素都是兩個元素而不是一個元組的列表,那麼爲了在保留原始字典中的列表的同時修改列表中的一個單一值,需要進行深層複製。 有關淺拷貝和深拷貝之間區別的更多信息,請參閱copy文檔。

+0

這不是一個副本,甚至不是淺的;它只是對* same *對象的另一個引用。 –

+0

@DanielRoseman你是對的,我解決了錯誤的解釋。謝謝! – albertoql

0

你在你的代碼下面的語句:

new_calibration = calibration 

這意味着如果你改變new_calibration,你也在改變校準,這就是爲什麼變化會反映在打印語句。

0

new_calibration = calibration只是表示new_calibration指的是與calibration所指的相同的對象。如果你想製作一個副本,使用dict.copy()方法:

new_calibration = calibration.copy() 

此外,new_calibration = {}是無用的,如果你要做的是重新定義new_calibration