Onyx logo

Previous topic

onyx.grid.griddy – >>> True

Next topic

onyx.grid.gridmap – Object for doing gridmap work.

This Page

onyx.grid.gridtools – Low-level support for transparently using the Sun Grid Engine (SGE) from Python

code.

onyx.grid.gridtools.serialize_function(f)

Turn a function into a string. The function can be reconstituted via unserialize_function().

The function must not have a closure. Note that it is somewhat risky for the function to refer to globals in the module in which it is defined. Specifically, non-picklable items and double-underscore items from the global environment of the function will not be available in the reconstituted function. Strings and numbers are OK, as are any built-in containers of these, including nested containers. But any modules or packages that the function needs must be imported within the body of the function. Also, the reconstituted function inherits the builtins of the reconstituting environment.

>>> x = 10
>>> y = attrdict((('a', 4), ('b', 5)))
>>> def f1(a, b=None, c='xx', d=10):
...   "a testing function"
...   import math
...   return int(math.floor(2 * a * x * len(y)))
>>> f1(3)
120
>>> s = serialize_function(f1)
>>> f2 = unserialize_function(s)
>>> f2(3)
120
>>> def fact1(n):
...   return 1 if n <= 1 else n * fact1(n-1)
>>> fact1(10)
3628800
>>> serialized_fact1 = serialize_function(fact1)
>>> unserialize_function(serialized_fact1)(10)
3628800
>>> serialize_function(1)
Traceback (most recent call last):
  ...
ValueError: expected a callable Python function, got a 'int'
>>> def func_maker(a):
...  def func(b): return a * b
...  return func
>>> f3 = func_maker(10)
>>> f3(2)
20
>>> serialize_function(f3) 
Traceback (most recent call last):
  ...
ValueError: unexpected closure for function 'func', referencing: 'a'
>>> with debugprint.DebugPrint('serialize'):
...   s1 = serialize_function(f1) 
serialize: dir 'f1'
serialize:   'func_closure' None
serialize:   'func_code' <code object f1 at 0x..., file "<doctest __main__.serialize_function[...]>", line 1>
serialize:   'func_defaults' (None, 'xx', 10)
serialize:   'func_dict' ()
serialize:   'func_doc' 'a testing function'
serialize:   'func_globals' (...)
serialize:   'func_name' 'f1'
serialize: dir func_code
serialize:   'co_argcount' 4
serialize:   'co_cellvars' ()
serialize:   'co_code' 'd\x01\x00d\x02\x00...'
serialize:   'co_consts' ('a testing function', -1, None, 2)
serialize:   'co_filename' '<doctest __main__.serialize_function[...]>'
serialize:   'co_firstlineno' 1
serialize:   'co_flags' ...
serialize:   'co_freevars' ()
serialize:   'co_lnotab' '\x...'
serialize:   'co_name' 'f1'
serialize:   'co_names' ('math', 'int', 'floor', 'x', 'len', 'y')
serialize:   'co_nlocals' 5
serialize:   'co_stacksize' ...
serialize:   'co_varnames' ('a', 'b', 'c', 'd', 'math')
serialize: func_name: 'f1'
serialize: func_co_s:
serialize:   'co_argcount' 4
serialize:   'co_nlocals' 5
serialize:   'co_stacksize' ...
serialize:   'co_flags' ...
serialize:   'co_code' 'd\x01\x00d\x02\x00...'
serialize:   'co_consts' ('a testing function', -1, None, 2)
serialize:   'co_names' ('math', 'int', 'floor', 'x', 'len', 'y')
serialize:   'co_varnames' ('a', 'b', 'c', 'd', 'math')
serialize:   'co_filename' '<doctest __main__.serialize_function[...]>'
serialize:   'co_name' 'f1'
serialize:   'co_firstlineno' 1
serialize:   'co_lnotab' '\x...'
serialize: func_globals:
serialize:   x int
serialize:   y attrdict
serialize: func_defaults: (None, 'xx', 10)
>>> with debugprint.DebugPrint('unserialize'):
...   unserialize_function(s1) 
unserialize: func_name: 'f1'
unserialize: func_co_s:
unserialize:   'co_argcount' 4
unserialize:   'co_nlocals' 5
unserialize:   'co_stacksize' ...
unserialize:   'co_flags' ...
unserialize:   'co_code' 'd\x01\x00d\x02\x00...'
unserialize:   'co_consts' ('a testing function', -1, None, 2)
unserialize:   'co_names' ('math', 'int', 'floor', 'x', 'len', 'y')
unserialize:   'co_varnames' ('a', 'b', 'c', 'd', 'math')
unserialize:   'co_filename' '<doctest __main__.serialize_function[...]>'
unserialize:   'co_name' 'f1'
unserialize:   'co_firstlineno' 1
unserialize:   'co_lnotab' '\x...'
unserialize: func_globals:
unserialize:   x int
unserialize:   y attrdict
unserialize: func_defaults: (None, 'xx', 10)
unserialize: dir 'f1'
unserialize:   'func_closure' None
unserialize:   'func_code' <code object f1 at 0x..., file "<doctest __main__.serialize_function[...]>", line 1>
unserialize:   'func_defaults' (None, 'xx', 10)
unserialize:   'func_dict' {}
unserialize:   'func_doc' 'a testing function'
unserialize:   'func_globals' {...}
unserialize:   'func_name' 'f1'
unserialize: dir func_code
unserialize:   'co_argcount' 4
unserialize:   'co_cellvars' ()
unserialize:   'co_code' 'd\x01\x00d\x02\x00...'
unserialize:   'co_consts' ('a testing function', -1, None, 2)
unserialize:   'co_filename' '<doctest __main__.serialize_function[...]>'
unserialize:   'co_firstlineno' 1
unserialize:   'co_flags' ...
unserialize:   'co_freevars' ()
unserialize:   'co_lnotab' '\x...'
unserialize:   'co_name' 'f1'
unserialize:   'co_names' ('math', 'int', 'floor', 'x', 'len', 'y')
unserialize:   'co_nlocals' 5
unserialize:   'co_stacksize' ...
unserialize:   'co_varnames' ('a', 'b', 'c', 'd', 'math')
<function f1 at 0x...>
onyx.grid.gridtools.unserialize_function(s)

Create and return a function using the string, s, which was created by serialize_function(). See serialize_function() for some cautions about using this mechanism.

Test this with the subtle example of the serialized recursive function from above.

Show that the name is not bound

>>> fact1
Traceback (most recent call last):
  ...
NameError: name 'fact1' is not defined

Now unserialize and use it

>>> serialized_fact1 =  "(S'fact1'\np1\n(I1\nI1\nI4\nI41027\nS'|\\x00\\x00d\\x01\\x00j\\x01\\x00o\\x05\\x00\\x01d\\x01\\x00S\\x01|\\x00\\x00t\\x00\\x00|\\x00\\x00d\\x01\\x00\\x18\\x83\\x01\\x00\\x14S'\np2\n(NI1\ntp3\n(g1\ntp4\n(S'n'\ntp5\nS'<doctest __main__.serialize_function[7]>'\np6\ng1\nI1\nS'\\x00\\x01'\np7\ntp8\n(dp9\nNtp10\n."
>>> unserialize_function(serialized_fact1)(10) 
3628800

But

>>> fact1
Traceback (most recent call last):
  ...
NameError: name 'fact1' is not defined

Note

As of 2010_04_16, HSW is not sure how the above manages to work, given that fact1 is still not bound. Guessing that it was bound in the scope that the doctest establishes.