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 .
source to share
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
notNone
, [__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.
source to share