Python 设置值时调用函数

Python 设置值时调用函数,python,python-3.x,dictionary,observer-pattern,Python,Python 3.x,Dictionary,Observer Pattern,使用observer模式,我有一个子类dict,在这个子类中,每当dict中的值发生变化时,我重写uuu setitem_uuuuu调用一个函数。这对于直接赋值(如my_dict[key]=1234)非常有效,但当我想要更改存储在dict中的数组中的值(如my_dict[key][0]=1)时,则不起作用 由于这是一个异步应用程序,我的一个想法是在uuu getitem_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

使用observer模式,我有一个子类dict,在这个子类中,每当dict中的值发生变化时,我重写uuu setitem_uuuuu调用一个函数。这对于直接赋值(如my_dict[key]=1234)非常有效,但当我想要更改存储在dict中的数组中的值(如my_dict[key][0]=1)时,则不起作用

由于这是一个异步应用程序,我的一个想法是在uuu getitem_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

处理这个问题的最佳方法是什么?每当我想在dict中存储数组时,我不想使用自定义数组

编辑:这是课程

class SettingsTable(dict):
    def __init__(self, seq=None, **kwargs):
        super().__init__({}, **kwargs)
        self._post_process_map = {}

    def add_post_process(self, key, process, *args):
        if not self._post_process_map.__contains__(key):
            self._post_process_map[key] = []
        self._post_process_map[key].append((process, *args))

    def __setitem__(self, key, value):
        old_val = None
        if self.keys().__contains__(key):
            old_val = self[key]

        super().__setitem__(key, value)
        self._run_on_change_funcs(key, value, old_val)

    def _run_on_change_funcs(self, key, value, old_val):
        if not old_val.__eq__(value):
            if self._post_process_map.__contains__(key):
                for func in self._post_process_map[key]:
                    if func[1]:
                        func[0](func[1])
                    else:
                        func[0]()

此外,几年前在Python中对内置类型进行子类化曾经是个坏主意。除此之外,我认为没有一个简明的解决方案可以让dict意识到其任何价值观的变化。你需要这个功能做什么?

也许你可以写一个list的子类,也可以重写它的_getitem_uuuu函数,只要你的dict子类_getitem_uu函数收到一个list类型值,你就会使用这个类。这是一个有点黑客的解决方案,但它应该在您的情况下工作

def change_item(val):
    print 'item changed: ' + str(val)

class MyList(list):
    def __setitem__(self, key, val):
        change_item(val)
        list.__setitem__(self, key, val)

class MyDict(dict):
    def __setitem__(self, key, val):
        change_item(val)
        if isinstance(val, list):
            dict.__setitem__(self, key, MyList(val))
        else:
            dict.__setitem__(self, key, val)

md = MyDict()
md['a'] = 1
md['d'] = ['c', 'd', 'e', 'f']
md['d'][0] = 'b'
我得到的输出测试是:

item changed: 1
item changed: ['c', 'd', 'e', 'f']
item changed: b
更新: 我刚查过你的密码。我采用了与建议相同的方法,但我也将dictionary引用及其键存储到MyList对象中,这样每当MyList对象更改时,它都会创建一个重复的MyList对象,为其指定新值,并将dictionary对象在键引用处的值指定为与重复的MyList对象相等,从而触发SettingsTable的_setitem __函数。我在uuu setitem_uuuuu函数中添加了一个printvalue行,以测试代码通过md['d'][0]='b'行时是否调用它


你不帮忙怎么办?听起来他们有同样的问题。你可以让你的uuu setitem接受元组,这样你就不用我的dict[key][0]=1,而是用我的dict[key,0]=1。那么所有特殊的大小写都在dict子类中。当然,这并不能阻止人们以第一种方式做事。然而,比较是正确的;您需要保留任何更改列表的副本。在my_dict[key][0]=1中,my_dict对任何作业都一无所知;对象看到的只是一个键的查找。唯一可行的方法是让对可变对象的每次查找都返回一个实际对象的包装版本,该实际对象本身有一个_setitem _;覆盖。当分配给一个可下标值的项时,是否要调用相同的函数?在Python中对内置类型进行子类化是个坏主意-为什么,我已经创建了一些有用的子类。对于早期版本的Python,我记得一些关于对内置类型进行子类化的在线警告,可能是因为随着语言的发展,API兼容性没有保证。我不确定今天的一般做法是什么。那可能是很久很久以前的事了,可能是在Python2.2中的类/类型统一之前。这很可能是我要做的。这也允许嵌套列表/目录,因为它们可以链接在一起。
class MyList(list):
    def __init__(self, dictionary, key, *args):
        super().__init__(*args)
        self.dictionary = dictionary
        self.key = key
    def __setitem__(self, key, val):
        new_list = MyList(self.dictionary, self.key, list(self))
        list.__setitem__(new_list, key, val)
        self.dictionary[self.key] = new_list

class SettingsTable(dict):
    def __init__(self, seq=None, **kwargs):
        super().__init__({}, **kwargs)
        self._post_process_map = {}

    def add_post_process(self, key, process, *args):
        if not self._post_process_map.__contains__(key):
            self._post_process_map[key] = []
        self._post_process_map[key].append((process, *args))

    def __setitem__(self, key, value):
        old_val = None
        if self.keys().__contains__(key):
            old_val = self[key]

        if isinstance(value, list):
            value = MyList(self, key, value)

        super().__setitem__(key, value)
        self._run_on_change_funcs(key, value, old_val)

    def _run_on_change_funcs(self, key, value, old_val):
        print(value)
        if not old_val.__eq__(value):
            if self._post_process_map.__contains__(key):
                for func in self._post_process_map[key]:
                    if func[1]:
                        func[0](func[1])
                    else:
                        func[0]()

md = SettingsTable()
md['a'] = 1
md['d'] = ['c', 'd', 'e', 'f']
md['d'][0] = 'b'