变量在函数中被修改并且在不应该被修改时返回

时间:2016-03-26 19:29:35

标签: python

我正在使用以下程序:

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)因为这意味着我的变量校准已被修改,即使它没有从函数返回。

3 个答案:

答案 0 :(得分:0)

您的代码中包含以下语句:

new_calibration = calibration

这意味着如果您更改new_calibration,您也会更改校准,这就是更改反映在print语句中的原因。

答案 1 :(得分:0)

new_calibration = calibration仅表示new_calibration引用calibration引用的同一对象。如果要复制,请使用dict.copy()方法:

new_calibration = calibration.copy()

此外,如果您要做的只是重新定义new_calibration = {}new_calibration将毫无用处。

答案 2 :(得分:0)

问题在于,当您将现有字典分配给新变量时,实际上新变量指向同一个对象。您可以使用id函数基本检查对象的地址。在示例id(calibration)id(new_calibration)中,您会看到它们具有相同的地址。这就是为什么如果修改新词典也会修改原始字典的原因。

为了拥有一个实际的新副本,即您可以使用copy包,并使用deepcopy功能。您应该更改的行是new_calibration的初始化,即:

new_calibration = copy.deepcopy(calibration)

这导致保留原始变量。

请注意,在问题的代码中,浅拷贝也起作用,因为tuple是字典的元素,它是一个不可变对象。浅拷贝和深拷贝之间的区别基本上是第一个创建一个新的复合对象,并在可能的情况下添加复制对象中找到的引用,而后者递归创建新对象。在问题中,如果在字典中每个元素都是两个元素的列表而不是元组,那么为了在保留原始字典中的列表的同时仅修改列表的单个值,则需要深层复制。 有关浅拷贝和深拷贝之间差异的更多信息,请参阅copy文档。