Python如何从对象二维列表中按引用获取数值属性以同步修改原对象
解决不可变数值属性的同步修改问题
你遇到的核心问题确实是Python中整数、浮点数的不可变性——当你把item.value添加到list_of_values时,实际上是把这个数值的副本存进去了,修改副本自然不会影响原对象的属性。想要实现"类似引用"的效果,我们可以通过可变容器包装数值或者创建代理矩阵两种方式来解决,避免批量赋值的性能开销。
方案1:用可变对象包装数值
最简单的方式是把不可变的数值放到一个可变的容器里(比如自定义的类或者列表),这样原对象和数值列表共享的是同一个容器引用,修改容器内的数值就能同步到原对象。
自定义可变数值类(推荐,可读性好)
class MutableNumber: def __init__(self, value): self.value = value # 实现魔法方法,让它像普通数值一样操作 def __imul__(self, other): self.value *= other return self def __float__(self): return float(self.value) def __int__(self): return int(self.value) class A: def __init__(self, value): # 用MutableNumber包装数值 self.value = MutableNumber(value) # 初始化对象矩阵和数值列表 list_of_objects = [] list_of_values = [] for i in range(2): list_of_objects.append([]) list_of_values.append([]) for j in range(2): item = A(2) list_of_objects[i].append(item) # 存入包装后的对象,而非原始数值 list_of_values[i].append(item.value) # 查看初始值 print([[int(v) for v in row] for row in list_of_values]) # 输出 [[2,2],[2,2]] # 修改数值列表中的元素 list_of_values[1][1] *= 3 # 原对象的属性同步更新 print(list_of_objects[1][1].value.value) # 输出 6
用列表快速包装(无需额外类)
如果不想新增类,也可以直接用列表作为容器:
class A: def __init__(self, value): self.value = [value] # 用列表包装数值 list_of_objects = [] list_of_values = [] for i in range(2): list_of_objects.append([]) list_of_values.append([]) for j in range(2): item = A(2) list_of_objects[i].append(item) list_of_values[i].append(item.value) print([[v[0] for v in row] for row in list_of_values]) # [[2,2],[2,2]] list_of_values[1][1][0] *= 3 # 修改列表内的数值 print(list_of_objects[1][1].value[0]) # 6
方案2:创建代理矩阵(无需修改原类)
如果不能修改A类的结构,更优雅的方式是实现一个代理矩阵类,它直接映射到原对象的value属性。操作代理矩阵时,本质是直接读写原对象的属性,完全不需要单独维护数值列表。
class ObjectMatrixProxy: def __init__(self, obj_matrix, attr_name): self.obj_matrix = obj_matrix self.attr_name = attr_name # 支持二维索引访问 def __getitem__(self, indices): i, j = indices return getattr(self.obj_matrix[i][j], self.attr_name) def __setitem__(self, indices, value): i, j = indices setattr(self.obj_matrix[i][j], self.attr_name, value) # 支持按行遍历 def __iter__(self): for row_idx, row in enumerate(self.obj_matrix): yield RowProxy(self, row_idx) class RowProxy: def __init__(self, matrix_proxy, row_idx): self.matrix_proxy = matrix_proxy self.row_idx = row_idx def __getitem__(self, col_idx): return self.matrix_proxy[self.row_idx, col_idx] def __setitem__(self, col_idx, value): self.matrix_proxy[self.row_idx, col_idx] = value # 初始化原对象矩阵 list_of_objects = [] for i in range(2): list_of_objects.append([]) for j in range(2): item = A(2) list_of_objects[i].append(item) # 创建代理矩阵,绑定到"value"属性 value_matrix = ObjectMatrixProxy(list_of_objects, "value") # 像操作普通矩阵一样使用 print([[value_matrix[i,j] for j in range(2)] for i in range(2)]) # [[2,2],[2,2]] value_matrix[1,1] *= 3 print(list_of_objects[1][1].value) # 6
这个方案特别适合你的卷积操作场景:你可以直接用value_matrix作为数值矩阵参与运算,所有修改都会实时同步到原对象的value属性,完全不需要额外的同步步骤。
为什么这些方案有效?
Python中虽然不可变类型(int、float)无法直接引用,但可变对象(自定义类实例、列表)的引用是可以共享的。我们通过让原对象和数值列表/代理矩阵共享同一个可变对象的引用,实现了修改的同步性。
内容的提问来源于stack exchange,提问作者dunajovm




