将回调附加到Counter()值

时间:2015-01-02 19:47:07

标签: python callback onchange

提供的所有代码都在python 3.3中。

我们假设我创建了以下Counter()对象:

>>> from collections import Counter
>>> g = Counter(a=2, b=5, c=6, d = 3)
>>> g
Counter({'a': 2, 'b': 5, 'd': 3, 'c': 6})

我现在可以通过简单地执行类似

的操作来更改计数器中的所有值
>>> g['b']=4

然而,我想检测来自Counter的特定值何时更改。当发生这种情况时,我想要执行一个函数,然后从计数器增加另一个特定值(如果它可以直接执行,没有函数 - 让我知道)。
例如,如果' a'递增,' c'并且' d'应该也是。

背景:
我正在编写一种算法,在字符串中搜索具有某些属性的子字符串,将这些子字符串写入列表,然后在子字符串中搜索更细小的子字符串,将它们分配给更高的子字符串。当最终函数计算出这些子串的所有出现时,我不希望它遍历子串的每个层次结构,而只需要递增更高的子串。附加的回调应该增加所有子子串。
由于我无法一次性添加所有回调,使用某种方法将回调添加到运行中的值会很棒。

1 个答案:

答案 0 :(得分:0)

正如我在评论中提到的,您需要覆盖__setitem__,无论是在您创建的Counter的新子类中,还是在您创建的新的从头开始的类中。

但是,您的评论表明您确实要覆盖g['a'] += 1,这更有问题。除非对象g['a'](不是g)定义了自己的__iadd__方法(整数没有),否则g['a'] += 1g['a'] = g['a'] + 1相同。这意味着g永远不会看到添加的1;它只会在添加1之后看到新的结果值。换句话说,如果g['a']为2而您g['a'] += 1,则g永远不会看到1;它只看到3(这是为其当前值加1后得到的)。

如果您想使用“增量”差异进行处理,则必须自行反映。下面是一个简单的示例,其中为字符串键设置新值也会更改其所有单个字符的值,并通过原始键的旧值和新值之间的差值递增它们:

class MagicCounter(collections.Counter):
    def __setitem__(self, key, val):
        # see how much is being "added"
        diff = val - self[key]
        super(MagicCounter, self).__setitem__(key, val)
        if len(key) > 1:
            for item in key:
                self[item] += diff

然后:

>>> c = MagicCounter()
>>> c['a'] = 1
>>> c['b'] = 1
>>> c['c'] = 1
>>> c
MagicCounter({'a': 1, 'c': 1, 'b': 1})
>>> c['abc'] += 1
>>> c
MagicCounter({'a': 2, 'c': 2, 'b': 2, 'abc': 1})