You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动