简体   繁体   English

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

[英]Passing a mutable variable to a second variable doesn't always work as expected. Why? Is there a workaround to keep the original variable reference?

Passing a mutable variable to a second variable doesn't always work as expected. 将可变变量传递给第二个变量并不总是能按预期工作。 Why? 为什么? Is there a workaround to keep the original variable reference? 有没有变通方法来保留原始变量引用?

Example: 例:

>>> 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]

Your assumption in the comment: 您在评论中的假设:

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

Is wrong . 错的

When you use slicing on list s , you create a shallow copy , not a view . list s上使用切片 ,将创建浅表副本而不是 视图 So those are two independent lists that operate differently. 因此,这是两个独立的列表,它们的操作方式不同。 Therefore changes to ref will not reflect on listA and vice versa. 因此,对ref更改将不会反映在listA ,反之亦然。

Note that the elements in the list , are still the same. 请注意, 列表中的元素仍然相同。 So the memory will look like: 因此,内存将如下所示:

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

Here that does not matter, since int s are immutable. 此处无关紧要,因为int是不可变的。 But if you would for instance call a method on an element of listA that changes the state of that object, the change will also reflect when you refer to that element through ref[0] for instance. 但是,例如,如果您要对listA元素上的方法调用以更改该对象的状态,则该更改还将反映在您通过ref[0]该元素时。

This behavior is not always the case, for instance numpy arrays use views when slicing is done. 这种行为并非总是如此,例如,切片时numpy数组会使用视图 For instance: 例如:

>>> 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])

You should always consult the documentation, like here for numpy arrays: 您应该始终查阅文档,例如此处有关numpy数组的信息:

(...) (...)

All arrays generated by basic slicing are always views of the original array. 通过基本切片生成的所有阵列始终都是原始阵列的视图

(...) (...)

Creating a listview 创建一个listview

You could construct a view on a list, by defining a class like: 您可以通过定义类似以下的类来在列表上构造视图:

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

Then you can construct a view like: 然后,您可以构建如下视图:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM