Python 2.6.5 defaultdict override __setitem__ infinite recursion

I would like to implement a dictionary that would perform certain checks on inserted keys, for example see below:

from collections import defaultdict

class CheckingDict(defaultdict):

    def __init__(self, *args, **kwargs):
        super(CheckingDict, self).__init__(*args, **kwargs)

    def __setitem__(self, key, value):
        if not super(CheckingDict, self).__missing__(key):
            raise ValueError("Key {key} is already present".format(key=key))
        else:
            return defaultdict.__setitem__(self, key, value)

a = CheckingDict(lambda: None)
a[1] = 1

      

The problem with the above code is that it gives me infinite recursion. So the question is why and how to do it right?

I don't want to use composition, as defaultdict

I will have to write a lot more code to get all the functions .

+3


source to share


1 answer


This __missing__

is causing the problem, and please note that:

  • It makes no sense to define __init__

    if it only calls the superclass; and
  • You are not using super

    when you actually set the element.

Working implementation:

class CheckingDict(defaultdict):

    def __setitem__(self, key, value):
        if key in self:
            raise ValueError("Key {!r} is already present".format(key))
        super(CheckingDict, self).__setitem__(key, value)

      




So why does the call __missing__

cause __setitem__

, which leads to recursion? This method doesn't just tell you what's missing key

; per documentation (emphasis mine):

If default_factory

not None

, [ __missing__

] is called with no arguments, specify a default value for the given key, this value is inserted into the dictionary for the key and returned.

This __missing__

, which actually puts the default in the dictionary if the key doesn't already exist, which means it has to call __setitem__

for it.

+4


source







All Articles