使用 __set__ 和 __setitem__ 修改 Python 中类似列表的属性时自动更新类属性

问题描述 投票:0回答:1

我有一个带有属性

ax_mask
的类。该属性类似于列表。当我更改整个属性或仅更改其中的一个元素时,我需要更新类中的其他属性 (
window
)(即应调用函数
update()
来处理更新逻辑)。

我尝试将属性实现为类似对象的描述符。这是我的代码:

import numpy as np


class AxMask:
    def __set_name__(self, owner, name):
        self.public_name = name
        self.private_name = '_' + name

    def __get__(self, obj, objtype=None):
        value = getattr(obj, self.private_name)
        return value

    def __set__(self, obj, value):
        setattr(obj, self.private_name, value)
        obj.update()

    def __setitem__(self, item, value):
        # change item in ax_mask to value
        # call Window.update()
        pass


class Window:
    ax_mask = AxMask()  # init descriptor like object

    def __init__(self, arr):
        self.arr = np.asarray(arr)
        self.window = self.arr  # init window
        shape = self.arr.shape
        self.ax_mask = [np.ones((d,), dtype=bool) for d in shape]  # init mask for each axis of arr with all True

    def update(self):
        # update window to only the rows/cols which are unmasked
        ix_ = np.ix_(*self.ax_mask)
        self.window = self.arr[ix_]

if __name__ == '__main__':
    m, n = (10, 5)
    test_arr = np.arange(m)[:, np.newaxis] + np.zeros((m, n), dtype=int)
    >>> test_arr
    array([[0, 0, 0, 0, 0],
           [1, 1, 1, 1, 1],
           [2, 2, 2, 2, 2],
           [3, 3, 3, 3, 3],
           [4, 4, 4, 4, 4],
           [5, 5, 5, 5, 5],
           [6, 6, 6, 6, 6],
           [7, 7, 7, 7, 7],
           [8, 8, 8, 8, 8],
           [9, 9, 9, 9, 9]])

    w = Window(test_arr)
    row_mask = np.ones((m,), dtype=bool)
    row_mask[5::] = False
    >>> row_mask
    array([True, True, True, True, True, False, False, False, False,
           False])

    w.ax_mask[0] = row_mask
    >>> w.window
    array([[0, 0, 0, 0, 0],
           [1, 1, 1, 1, 1],
           [2, 2, 2, 2, 2],
           [3, 3, 3, 3, 3],
           [4, 4, 4, 4, 4],
           [5, 5, 5, 5, 5],
           [6, 6, 6, 6, 6],
           [7, 7, 7, 7, 7],
           [8, 8, 8, 8, 8],
           [9, 9, 9, 9, 9]])

但是我希望

w.window
看起来像这样:

>>> w.window
array([[0, 0, 0, 0, 0],
    [1, 1, 1, 1, 1],
    [2, 2, 2, 2, 2],
    [3, 3, 3, 3, 3],
    [4, 4, 4, 4, 4]])

欢迎任何想法!

python oop getter-setter python-descriptors
1个回答
0
投票

感谢评论,我想出了一个解决方案。我希望这会对某人有所帮助。这是代码,我用

AxMask
替换了
ObservableList
类:

import numpy as np


class ObservableList(list):
    """Notifies the owner when an item is set"""
    def __init__(self, iterable, owner):
        super().__init__(iterable)
        self.owner = owner

    def __setitem__(self, key, value):
        super().__setitem__(key,value)
        self.notify()

    def notify(self):
        self.owner.update()


class Window:
    def __init__(self, arr):
        self.arr = np.asarray(arr)
        self.window = self.arr
        shape = self.arr.shape
        self._ax_mask = ObservableList([np.ones((d,), dtype=bool) for d in shape], self)

    @property
    def ax_mask(self):
        return self._ax_mask

    @ax_mask.setter
    def ax_mask(self, iterable):
        self._ax_mask = ObservableList(iterable, self)
        self.update()

    def update(self):
        ix_ = np.ix_(*self.ax_mask)  # advanced indexing -> no view, but copy;
        self.window = self.arr[ix_]

有任何建议欢迎提出!

© www.soinside.com 2019 - 2024. All rights reserved.