What you're actually trying to do is pickle your recursive defaultdict
. And you don't care whether you get back a dict
or a defaultdict
when unpickling.
While there are a number of ways to solve this (e.g., create a defaultdict
subclass with its own pickling, or explicitly override the default one with copyreg
), there's one that's dead trivial.
Notice the error you get when you try it:
>>> pickle.dumps(defdict)
PicklingError: Can't pickle <function <lambda> at 0x10d7f4c80>: attribute lookup <lambda> on __main__ failed
You can't pickle lambda
-defined functions, because they're anonymous, meaning there's no way they could ever be unpickled.
But there is literally no reason this function needs to be defined by lambda
. In particular, you don't even want it to be anonymous, because you're explicitly giving it a name. So:
def factory(): return defaultdict(factory)
And you're done.
Here it is in action:
>>> from collections import defaultdict
>>> def factory(): return defaultdict(factory)
>>> defdict = factory()
>>> defdict['one']['two']['three']['four'] = 5
>>> import pickle
>>> pickle.dumps(defdict)
b'\x80\x03ccollections\ndefaultdict\nq\x00c__main__\nfactory\nq\x01\x85q\x02Rq\x03X\x03\x00\x00\x00oneq\x04h\x00h\x01\x85q\x05Rq\x06X\x03\x00\x00\x00twoq\x07h\x00h\x01\x85q\x08Rq\tX\x05\x00\x00\x00threeq\nh\x00h\x01\x85q\x0bRq\x0cX\x04\x00\x00\x00fourq\rK\x05ssss.'
There are other cases where using lambda
instead of def
for no good reason will cause problems—you can't introspect your functions as well at runtime, you get worse tracebacks in the debugger, etc. Use lambda
when you want an inherently-anonymous function, or a function you can define in the middle of an expression, but don't use it to save three characters of typing.