【问题标题】:How to use indexing with the @property decorator如何通过 @property 装饰器使用索引
【发布时间】:2021-12-28 13:17:11
【问题描述】:

我正在尝试使用 python 装饰器更改作为矩阵的类属性的某些索引。问题是我不知道如何使用 setter 方法指定索引。我的代码是这样的:

class A():
    def __init__(self, N, M):
        self.large_matrix = np.zeros(N, M)
        self.some_set = [1,2,3]
    
    @property
    def matrix(self):
        return self.large_matrix[:,self.some_set]
    
    @matrix.setter
    def matrix(self,value):
        self.large_matrix[:,self.some_set] = value

有了这个类,我想通过访问较小的矩阵来改变大矩阵的某些值,例如:

self.matrix[index] = value

但这不起作用。代码运行不会引发错误,但大矩阵中的值不会改变。 相反,如果我输入

self.matrix = value

它工作得很好。我还应该提到,拥有装饰器是至关重要的,因为属性 self.someset 有时会发生变化。因此,我希望大型矩阵在我不处理的那些索引上保持不变,但我确实需要将它们存储在类中以供以后参考。

我找到的一个解决方案如下:

m = self.matrix.copy()
m[index] = value
self.matrix = m

这可行,但我认为代码会变得慢得多(这是一个因素),并且在代码中的任何地方都进行更改是很费力的。澄清;矩阵需要在类中访问。是否有任何解决方案来更改 @matrix.setter 装饰器和方法,以使代码保持高效并且我不必在任何地方更改代码?

【问题讨论】:

  • 如果你把print() 放在两个函数中,那么你应该看到matrix[index] = value 运行getter,而不是setter - 得到matrix - 然后它运行[4] 值来自getter。唯一的想法是使用__getitme____setitem__ 而不是matrix
  • 我对您的示例代码感到相当困惑,因为它没有使用属性表示法,这是属性的来源。您是否正在创建 A 的实例 a = A(5,5) 和所有在您的示例中对matrix 的引用真的是a.matrix?请把你的例子变成minimal reproducible example
  • @blckknght 我现在更改了它,为不明确表示歉意。只是为了澄清;在示例中,我在同一个类中调用矩阵来执行计算。

标签: python class oop decorator


【解决方案1】:

如果您将print() 放在两个函数中,那么您应该会看到matrix[index] = value 运行getter,而不是setter。它运行getter 以获取matrix,然后它运行[4] 来自getter 的值。但是getter 使用索引[:,self.some_set],所以它从large_matrix 复制数据并返回新的array,它无法访问原始array 中的数据。

唯一的想法是创建一个新类,它将获得large_matrixsome_set,它将与这个子矩阵一起工作。而原来的matrix()会在这个矩阵的所有项中获取这个类或者设置值

import numpy as np

class SubMatrix():
    def __init__(self, matrix, some_set):
        self.matrix = matrix
        self.some_set = some_set

    def __getitem__(self, index):
        print('getitem:', index)
        return self.matrix[index, self.some_set]

    def __setitem__(self, index, value):
        print('setitem:', index, value)
        self.matrix[index, self.some_set] = value


class A():
    def __init__(self, N, M):
        self.large_matrix = np.zeros((N, M))
        self.some_set = [1,2,3]
        self.sub_matrix = SubMatrix(self.large_matrix, self.some_set)

    @property
    def matrix(self):
        print('getter')
        return self.sub_matrix
    
    @matrix.setter
    def matrix(self, value):
        print('setter')
        self.sub_matrix[:] = value

# --- main ---

m = A(5, 5)

print(">>> m.matrix[4] = 1")
m.matrix[4] = 1
print(m.large_matrix)
print('---')

print(">>> m.matrix = 1")
m.matrix = 1
print(m.large_matrix)
print('---')

print(">>> m.matrix[1] = [4,3,2]")
m.matrix[1] = [4,3,2]
print(m.large_matrix)
print('---')

print(">>> m.matrix[2:4] = [1,2,3]")
m.matrix[2:4] = [1,2,3]
print(m.large_matrix)
print('---')

print(">>> m.matrix[1]")
print(m.matrix[1])
print('---')

结果:

>>> m.matrix[4] = 1
getter
setitem: 4 1
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 1. 1. 1. 0.]]
---
>>> m.matrix = 1
setter
setitem: slice(None, None, None) 1
[[0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]]
---
>>> m.matrix[1] = [4,3,2]
getter
setitem: 1 [4, 3, 2]
[[0. 1. 1. 1. 0.]
 [0. 4. 3. 2. 0.]
 [0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]
 [0. 1. 1. 1. 0.]]
---
>>> m.matrix[2:4] = [1,2,3]
getter
setitem: slice(2, 4, None) [1, 2, 3]
[[0. 1. 1. 1. 0.]
 [0. 4. 3. 2. 0.]
 [0. 1. 2. 3. 0.]
 [0. 1. 2. 3. 0.]
 [0. 1. 1. 1. 0.]]
---
>>> m.matrix[1]
getter
getitem: 1
[4. 3. 2.]

编辑:

如果你会在matrix 中使用多维index 就像

m.matrix[2:4,2] = [9]

那么它会使用

    def __setitem__(self, index, value):
        print('setitem:', index, value)
        if isinstance(index, tuple):
            self.matrix[index] = value   # ie. [2:4, 2]
        else:
            self.matrix[index, self.some_set] = value   # [2:4]

但这使用large_matrix 的索引,而不是matrix


print(">>> m.matrix[2:4,2] = [1,2,3]")
m.matrix[2:4,2] = [9]
print(m.large_matrix)
print('---')

结果:

>>> m.matrix[2:4] = [1,2,3]
getter
setitem: (slice(2, 4, None), 2) [9]
[[0. 1. 1. 1. 0.]
 [0. 4. 3. 2. 0.]
 [0. 1. 9. 3. 0.]
 [0. 1. 9. 3. 0.]
 [0. 1. 1. 1. 0.]]
---

要在Matrix 中使用自己的索引,需要更复杂的代码来重新计算索引。

【讨论】:

  • 太好了,这似乎有效,谢谢!
猜你喜欢
  • 2011-03-09
  • 2021-11-27
  • 1970-01-01
  • 2014-10-17
  • 1970-01-01
  • 2016-03-14
相关资源
最近更新 更多