python - 将可变变量传递给第二个变量并不总是按预期工作。为什么?是否有解决方法来保留原始变量引用?

标签 python

将可变变量传递给第二个变量并不总是按预期工作。为什么?是否有解决方法来保留原始变量引用?

例子:

>>> listA = [10,11,12,13,14]

# this works as I would expect it:
>>> ref = listA
>>> ref[0] = 20
>>> listA
[20, 11, 12, 13, 14]

# but this doesn't
>>> ref = listA[1:3]    # still making reference to a mutable (only part of it)
>>> ref
[11, 12]
>>> ref[0]=30
>>> listA
[20, 11, 12, 13, 14]

最佳答案

您在评论中的假设:

# still making reference to a mutable (only part of it)

错误

当您在 list 上使用切片时s,您创建了一个浅拷贝不是 View 。所以这是两个独立的列表,它们的运作方式不同。因此更改为 ref不会反射(reflection)listA反之亦然。

请注意,列表中的元素仍然是相同的。所以内存看起来像:

         +-------------------+         +-------+
listA -> |       list        |  ref -> |  list |
         +---+---+---+---+---+         +---+---+
         | o | o | o | o | o |         | o | o |
         +-|-+-|-+-|-+-|-+-|-+         +-|-+-|-+
           v   |   |   v   v             |   |
           20  |   |   13  14            |   |
               |   v                     |   |
               v   12 <------------------|---/
               11 <----------------------/

这里没关系,因为int s 是不可变的。但是,如果您要在 listA 的元素上调用一个方法更改该对象的状态,当您通过 ref[0] 引用该元素时,更改也会反射(reflect)出来例如。

这种行为并不总是,例如 numpy数组在切片完成时使用 View 。例如:

>>> import numpy as np
>>> a = np.arange(10)
>>> b = a[1:3] # slicing in numpy generates a "view"
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b
array([1, 2])
>>> b[0] = 5
>>> a
array([0, 5, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b
array([5, 2])

您应该始终查阅文档,例如 here对于 numpy 数组:

(...)

All arrays generated by basic slicing are always views of the original array.

(...)

创建 listview

您可以通过定义一个类来构建 ListView ,如下所示:

class listview:

    def __init__(self,data,frm=None,len=None):
        self.data = data
        self.frm = frm
        self.len = len

    def __getitem__(self,idx):
        if self.frm is not None:
            idx += self.frm
        if self.len is not None and idx >= self.len:
            raise Exception('Index out of range!')
        return self.data[idx]

    def __setitem__(self,idx,value):
        if self.frm is not None:
            idx += self.frm
        if self.len is not None and idx >= self.len:
            raise Exception('Index out of range!')
        self.data[idx] = value

    def __len__(self):
        frm = 0
        if self.frm is not None:
            frm = self.frm
        if self.len is not None:
            return min(self.len,len(self.data)-frm)
        return len(self.data)

    def __repr__(self):
        return 'listview(%s,%s,%s)'%(self.data,self.frm,self.len)

    # ... and so on

然后你可以构造一个像这样的 View :

>>> listA = [10,11,12,13,14]
>>> ref = listview(listA,1,2)
>>> ref[0] = 5
>>> listA
[10, 5, 12, 13, 14]

关于python - 将可变变量传递给第二个变量并不总是按预期工作。为什么?是否有解决方法来保留原始变量引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42975552/

相关文章:

python - 预期 TensorFlow 计算,发现内在

python - 在 GitLab 中导入 ZAP Docker 镜像

python - 匹配从开头到多字符子字符串第一次出现的一段文本

Python mod_wsgi 不工作

python - 使用 wxpython 重新绑定(bind)按钮

python - 为什么 concurrent.futures 不复制参数?

python - Django 中的模拟请求

python - 通过二值图像 Numpy 矩阵的矩阵运算计算均方误差

python - 你能给我指出一个大型 Python 开源项目吗?

python - 在python中强制重命名文件