首页 > 解决方案 > 如何在不影响python中的(引用)地址的情况下更改列表的内容?

问题描述

我正在将我的 C++ 代码移植到 Python。在 C++ 中,我经常使用引用来维护数据源和“指针”之间的一些连接。一开始,我以为 Python 没有指针的概念,但经过一番研究,我发现如果不应用 deepcopy,两个列表之间的赋值会保持对源列表的引用。在下面的代码中,我试图创建一些 numpy 数组的列表,并有一个外部变量“指向”该列表,因此对外部引用的任何修改都会相应地更改内部数据。

import numpy as np
import copy

class myList:
    _data = None

    def __init__(self):
        self._data = [np.array([1,2,3,4,5]), np.array([7,8,2,3,1]), np.array([9,9,3,7,5])]

    def getData(self, reference=False):
        if reference:
            return self._data
        else:
            return copy.deepcopy(self._data)

if __name__ == '__main__':
    dt = myList()
    ref = dt.getData(reference=True)

    print(id(dt._data), '  ', id(ref))
    ref[1][3] = (k+1) * 11
    print(dt)

上面的代码显示dt._dataref共享相同的地址,并且任何更改ref都会反映dt._data,反之亦然。但是如果我需要dt._data使用其他一些数据源来重置

if __name__ == '__main__':
    dt = myList()
    ref = dt.getData(reference=True)
    newSrc = [np.array([1, 1, 1, 1, 1]), np.array([2, 2, 2, 2, 2]), np.array([3, 3, 3, 3, 3])]
    dt._data = copy.deepcopy(newSrc)  
    print(id(dt._data), '  ', id(ref)) # different address shown

的地址dt._data将改变,而ref将保持不变。经过反复试验,我发现逐行执行分配似乎可以解决问题

if __name__ == '__main__':
    dt = myList()
    ref = dt.getData(reference=True)
    newSrc = [np.array([1, 1, 1, 1, 1]), np.array([2, 2, 2, 2, 2]), np.array([3, 3, 3, 3, 3])]
    for i in len(newSrc):
      dt._data[i] = copy.deepcopy(newSrc[i])

    print(id(dt._data), '  ', id(ref)) # sameaddress shown

我不确定这是否是解决问题的正确方法,但至少如果 newSrc 和 dt._data 的维度相同,它不会引发任何问题。但是如果 newSrc 的行数比 dt._data 多或少,这会导致问题吗?如果是,是否像 C/C++ 一样只是更改“指针”的内容(如 *pointer = ...)但保持地址不变Python?

标签: pythonlist

解决方案


如果我正确理解了您的问题,您的代码实际上可以按您的预期工作。修改 中的值后ref,修改类内的数组。只需更改代码的最后一行,即可看到差异为print(dt._data).

在您的代码中,当 时reference=True,对象ref的地址与dt._data. 不过,我强烈建议使用 alwaysdt._data以避免将来出现问题。为什么?因为如果您dt._data稍后在代码中进行初始化,ref则将不再指向其内容。

当您设置 时reference=Falseref将包含该时间点数组内容的精确副本。从那时起,它们将在您的代码中表现为完全不同的变量。


推荐阅读