【问题标题】:Attach callback to Counter() value将回调附加到 Counter() 值
【发布时间】:2015-01-02 19:47:06
【问题描述】:

提供的所有代码都在 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' 也应该增加。

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

【问题讨论】:

  • 您需要继承 Counter,覆盖 __setitem__,然后在那里进行检查。
  • @PadraicCunningham 请阅读上下文。我假设 c 和 d 是 a 的子串。也许我应该说得更清楚一点。
  • @BrenBarn 这是一个很好的解决方案,不幸的是,我需要在一个相当小的脚本中执行此操作,因为我必须将整个源代码添加到具有页数限制的文档中。我根本负担不起将 Counter() 子类化。尽管如此,很好的方法。如果一切都失败了,我会这样做并告诉我的老板我需要更多空间:)
  • @SmeltQuake:你必须这样做。您可以查看 Counter right here 的文档。那里没有关于回调的内容。 Counter 不支持任何开箱即用的东西。如果您在使用obj[item] = blah 设置对象的项目时需要特殊行为,则可以使用__setitem__。 (当然,您也可以编写自己的类来独立于 Counter 来执行此操作,但这并不会减少工作量。)

标签: python callback onchange


【解决方案1】:

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

但是,您的评论表明您确实想覆盖g['a'] += 1,这更有问题。除非对象g['a'](不是g)定义了自己的__iadd__ 方法(整数没有),否则g['a'] += 1 与g['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})

【讨论】:

  • 绝对很有帮助。实际上有一个不干净的解决方法,但我想我可以解决这个问题。非常感谢。
猜你喜欢
  • 1970-01-01
  • 2011-10-31
  • 2018-08-15
  • 1970-01-01
  • 2012-08-26
  • 2022-11-24
  • 2012-06-13
  • 2012-06-08
  • 1970-01-01
相关资源
最近更新 更多