douban/dpark — pull request #6 by JoshRosen (2012-07-26 01:32:38+00:00)
Title: Support serialization of recursive functions wtih dump_func()

This patch adds support for serialization of recursive functions with `dump_func()`. Previously, trying to serialize a recursive function resulted in infinite recursion:

```python
>>> from serialize import dump_func, load_func
>>> def fib(n): return n if n <= 1 else fib(n-1) + fib(n-2)
...
>>> dump_func(fib)
Traceback (most recent call last):
File "", line 1, in
File "serialize.py", line 58, in dump_func
glob[n] = dump_object(r)
File "serialize.py", line 25, in dump_object
return 1, dump_func(o)
File "serialize.py", line 58, in dump_func
glob[n] = dump_object(r)
File "serialize.py", line 25, in dump_object
return 1, dump_func(o)
...
File "serialize.py", line 47, in dump_func
if f.__module__ != '__main__':
RuntimeError: maximum recursion depth exceeded in cmp
```

The infinite recursion occurs because the function object itself appears in its own globals dictionary under the name `fib`.

This patch addresses this issue by replacing self-references with special placeholder objects before serialization. When deserializing a function, the placeholders are replaced by a wrapper function that calls a function stored in a list. This simulates a function pointer and allows a reference to the deserialized function to appear in that function's globals dictionary when it is constructed with `new.function()`.

After applying this patch, the recursive Fibonacci function is serializable:

```python
>>> dump_func(fib)
(0, '(\x05\x00\x00\x00c\x01\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00C\x00\x00\x00s,\x00\x00\x00|\x00\x00d\x01\x00k\x01\x00r\x10\x00|\x00\x00St\x00\x00|\x00\x00d\x01\x00\x18\x83\x01\x00t\x00\x00|\x00\x00d\x02\x00\x18\x83\x01\x00\x17S(\x03\x00\x00\x00Ni\x01\x00\x00\x00i\x02\x00\x00\x00(\x01\x00\x00\x00t\x03\x00\x00\x00fib(\x01\x00\x00\x00t\x01\x00\x00\x00n(\x00\x00\x00\x00(\x00\x00\x00\x00s\x07\x00\x00\x00R\x00\x00\x00\x00\x01\x00\x00\x00s\x00\x00\x00\x00{R\x00\x00\x00\x00(\x02\x00\x00\x00i\x03\x00\x00\x00s5\x00\x00\x00\x80\x02cserialize\nRecursiveFunctionPlaceholder\nq\x01)\x81q\x02}q\x03b.0R\x00\x00\x00\x00NN')
>>> load_func(dump_func(fib))(3)
2
```