numpy Python中的索引可管理属性

vuktfyat  于 2022-12-04  发布在  Python
关注(0)|答案(1)|浏览(136)

我需要添加一个自定义属性到一个类中,并使这个属性为“索引”。下面的代码片段说明了这个问题:

import numpy as np

class Test:
    def __init__(self):
        self.arr = np.array([[100, 200, 300],
                             [100, 155, 120],
                             [300, 110, 333],
                             [500, 180, 120]
                            ], dtype='object')

    @property
    def SecondRow(self):
        return self.arr[:, 1]

    # Workaround which always works
    @SecondRow.setter
    def SecondRow(self, data):
        idx, value = data
        self.arr[idx][1] = value

def func(test):
    print(test.SecondRow)

    # It works sometimes (depending if python makes a copy of self.arr[:, 1] or not).
    # In the case of this example, it will work. In another context, it may not work.
    test.SecondRow[2] = 500
    print(test.arr)

    # It works always but the code is not neat. I would like it to look as in the previous example.
    test.SecondRow = (2, 600)
    print(test.arr)

test = Test()
func(test)

输出为:

[200 155 110 180]
[[100 200 300]
 [100 155 120]
 [300 500 333]
 [500 180 120]]
[[100 200 300]
 [100 155 120]
 [300 600 333]
 [500 180 120]]

这里的输出是可以的。然而,在真实的的项目中,数组是巨大的,在创建一个'class Test'示例和调用'def func()'之间有许多中间调用,在某些情况下,python解释器会复制'self.arr[:,1]'(特别有问题的是单元测试),改变它不会影响实际的numpy数组'self.arr',而只是复制列。
如何以常规方式(如test.SecondRow [2])处理[index],同时仍能处理复制问题?
有什么需要帮忙的吗?

ryevplcw

ryevplcw1#

有一个稍微有点笨拙的方法来做你想做的事情,那就是捎带__setitem__

import numpy as np

class Test:
    def __init__(self):
        self.arr = np.array([[100, 200, 300],
                             [100, 155, 120],
                             [300, 110, 333],
                             [500, 180, 120]
                            ], dtype='object')
        
        # a control mechanism if there are multiple properties
        self.signal = None

    def __setitem__(self, idx, value):
        """Performs action according to specified signal."""
        
        if self.signal == "R1":
            self.arr[idx, 1] = value
        elif self.signal == "C0":
            self.arr[0, idx] = value
        
        self.signal = None # reset signal

    @property
    def SecondRow(self):
        self.signal = "R1"
        return self

    @property
    def FirstColumn(self):
        self.signal = "C0"
        return self

这应该可以让您在自订属性中建立索引,并修改数组,而不会发生任何问题。

def func(test):
    test.SecondRow[2] = 500
    print("Arr:\n", test.arr)

    test.FirstColumn[0] = -17
    print("Arr:\n", test.arr)
    
test = Test()
func(test)

输出量:

Arr:
 [[100 200 300]
 [100 155 120]
 [300 500 333]
 [500 180 120]]
Arr:
 [[-17 200 300]
 [100 155 120]
 [300 500 333]
 [500 180 120]]

缺点

虽然test.SecondRow[2] = 500现在应该没有任何问题,但我们已经失去了执行print(test.SecondRow)的能力,因为我们直接路由到self和setitem。

相关问题