将回调附加到 Counter() 值

Attach callback to Counter() value

提供的所有代码都在 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

但是,我想检测计数器的特定值何时更改。发生这种情况时,我希望执行一个函数,然后从计数器递增另一个特定值(如果可以直接执行此操作,而无需函数 - 让我知道)。
例如,如果 'a' 增加,'c' 和 'd' 也应该增加。

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

正如我在评论中提到的,您需要覆盖 __setitem__,或者在您创建的计数器的新子 class 中,或者在新的从头开始 class 你创造的。

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

如果你想使用"incremental"差异来做你的处理,你必须自己反算。这是一个简单的示例,其中为字符串键设置新值也会更改其所有单个字符的值,并根据原始键的旧值和新值之间的差异递增它们:

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})