为什么获取分配给另一个列表的列表的一部分不会改变原始列表?
Why is taking a slice of a list which is assigned to another list not changing the original?
我有一个 class 表示数学张量。 class 中的张量存储为单个列表,而不是另一个列表中的列表。这意味着 [[1, 2, 3], [4, 5, 6]]
将存储为 [1, 2, 3, 4, 5, 6]
。
我已经创建了一个 __setitem__()
函数和一个函数来处理在单列表格式时获取该张量的切片。例如,对于上述列表,slice(1, None, None)
将变为 slice(3, None, None)
。然而,当我为这个切片分配一个新值时,原始张量没有更新。
这是简化代码的样子
class Tensor:
def __init__(self, tensor):
self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.
def __setitem__(self, slices, value):
slices = [slices]
temp_tensor = self.tensor # any changes to temp_tensor should also change self.tensor.
for s in slices: # Here I would call self.slices_to_index(), but this is to keep the code simple.
temp_tensor = temp_tensor[slice]
temp_tensor = value # In my mind, this should have also changed self.tensor, but it hasn't.
也许我只是太蠢了,不明白为什么这不起作用。也许我真正的问题不仅仅是“为什么这行不通?”还有'is there a better way to do this?'。感谢您能给我的任何帮助。
备注:
列表的每个 'dimension' 必须具有相同的形状,因此 [[1, 2, 3], [4, 5]]
是不允许的。
此代码已大大简化,因为还有许多其他辅助函数和类似的东西。
在 __init__()
中,我会将列表展平,但正如我刚才所说的,为了简单起见,我将其与 self.slice_to_index()
.
一起省略了
您不应将 python 变量视为 c++
或 java
中的变量。将它们视为您贴在价值观上的标签。检查这个例子:
>>> l = []
>>> l.append
<built-in method append of list object at 0x7fbb0d40cf88>
>>> l.append(10)
>>> l
[10]
>>> ll = l
>>> ll.append(10)
>>> l
[10, 10]
>>> ll
[10, 10]
>>> ll = ["foo"]
>>> l
[10, 10]
如你所见,ll
变量首先指向同一个 l
列表,但后来我们只是让它指向另一个列表。修改后面的ll
不会修改l
指向的原始列表。
因此,在您的情况下,如果您希望 self.tensor
指向一个新值,只需这样做:
class Tensor:
def __init__(self, tensor):
self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.
def __setitem__(self, slices, value):
slices = [slices]
temp_tensor = self.tensor # any changes to the list pointed by temp_tensor will be reflected in self.tensor since it is the same list
for s in slices:
temp_tensor = temp_tensor[slice]
self.tensor = value
我有一个 class 表示数学张量。 class 中的张量存储为单个列表,而不是另一个列表中的列表。这意味着 [[1, 2, 3], [4, 5, 6]]
将存储为 [1, 2, 3, 4, 5, 6]
。
我已经创建了一个 __setitem__()
函数和一个函数来处理在单列表格式时获取该张量的切片。例如,对于上述列表,slice(1, None, None)
将变为 slice(3, None, None)
。然而,当我为这个切片分配一个新值时,原始张量没有更新。
这是简化代码的样子
class Tensor:
def __init__(self, tensor):
self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.
def __setitem__(self, slices, value):
slices = [slices]
temp_tensor = self.tensor # any changes to temp_tensor should also change self.tensor.
for s in slices: # Here I would call self.slices_to_index(), but this is to keep the code simple.
temp_tensor = temp_tensor[slice]
temp_tensor = value # In my mind, this should have also changed self.tensor, but it hasn't.
也许我只是太蠢了,不明白为什么这不起作用。也许我真正的问题不仅仅是“为什么这行不通?”还有'is there a better way to do this?'。感谢您能给我的任何帮助。
备注:
列表的每个 'dimension' 必须具有相同的形状,因此 [[1, 2, 3], [4, 5]]
是不允许的。
此代码已大大简化,因为还有许多其他辅助函数和类似的东西。
在 __init__()
中,我会将列表展平,但正如我刚才所说的,为了简单起见,我将其与 self.slice_to_index()
.
您不应将 python 变量视为 c++
或 java
中的变量。将它们视为您贴在价值观上的标签。检查这个例子:
>>> l = []
>>> l.append
<built-in method append of list object at 0x7fbb0d40cf88>
>>> l.append(10)
>>> l
[10]
>>> ll = l
>>> ll.append(10)
>>> l
[10, 10]
>>> ll
[10, 10]
>>> ll = ["foo"]
>>> l
[10, 10]
如你所见,ll
变量首先指向同一个 l
列表,但后来我们只是让它指向另一个列表。修改后面的ll
不会修改l
指向的原始列表。
因此,在您的情况下,如果您希望 self.tensor
指向一个新值,只需这样做:
class Tensor:
def __init__(self, tensor):
self.tensor = tensor # Here I would flatten it, but for now imagine it's already flattened.
def __setitem__(self, slices, value):
slices = [slices]
temp_tensor = self.tensor # any changes to the list pointed by temp_tensor will be reflected in self.tensor since it is the same list
for s in slices:
temp_tensor = temp_tensor[slice]
self.tensor = value