I am using defaultdict(set)
to populate an internal mapping in a very large data structure. After it's populated, the whole structure (including the mapping) is exposed to the client code. At that point, I don't want anyone modifying the mapping.
And nobody does, intentionally. But sometimes, client code may by accident refer to an element that doesn't exist. At that point, a normal dictionary would have raised KeyError
, but since the mapping is defaultdict
, it simply creates a new element (an empty set) at that key. This is quite hard to catch, since everything happens silently. But I need to ensure this doesn't happen (the semantics actually doesn't break, but the mapping grows to a huge size).
What should I do? I can see these choices:
Find all the instances in current and future client code where a dictionary lookup is performed on the mapping, and convert it to
mapping.get(k, {})
instead. This is just terrible."Freeze"
defaultdict
after the data structure is fully initialized, by converting it todict
. (I know it's not really frozen, but I trust client code to not actually writemapping[k] = v
.) Inelegant, and a large performance hit.Wrap
defaultdict
into adict
interface. What's an elegant way to do that? I'm afraid the performance hit may be huge though (this lookup is heavily used in tight loops).Subclass
defaultdict
and add a method that "shuts down" all thedefaultdict
features, leaving it to behave as if it's a regulardict
. It's a variant of 3 above, but I'm not sure if it's any faster. And I don't know if it's doable without relying on the implementation details.Use regular
dict
in the data structure, rewriting all the code there to first check if the element is in the dictionary and adding it if it's not. Not good.
dict.setdefault
method... No big deal – Ulbertodefaultdict
is that it overrides__getitem__
to add an element if needed. Maybe it does that usingsetdefault
method, maybe it implements the same logic directly without ever callingsetdefault
. Without relying on implementation details, I can't assume anything, can I? – Vansickledict
on tehdefaultdict
to dictify it – Unjustdefaultdict
, isn't it? (Not that I disagree, just want to understand the logic.) – Vansickledict
) is too expensive. – Vansickledict.setdefault
is implemented in C, and it does precisely whatdefaultdict.__getitem__
does. Shouldn't it be equally fast? – Vansickle