eval() and global variables

Peter Otten __peter__ at web.de
Fri Dec 19 10:36:53 CET 2008


Juan Pablo Romero Méndez wrote:

> The hack given by Peter works fine, except in this case:
> 
>>>> def aaaa(fn):
> ...     f2 = lambda x,y:(x,y,fn(x,y))
> ...     function = type(f2)
> ...     f3 = function(f2.func_code,dict())
> ...     print f3
> ...
>>>> aaaa(lambda x,y:x+y)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "<stdin>", line 4, in aaaa
> TypeError: arg 5 (closure) must be tuple
>>>>
> 
> 
> Strange...

The variable fn must be passed to the lambda somehow. You could return f2()
from aaaa(), and f2() would still have to "know" about it. This is called
a "closure".

>>> def f(): pass
...
>>> function = type(f)
>>> print function.__doc__
function(code, globals[, name[, argdefs[, closure]]])

Create a function object from a code object and a dictionary.
The optional name string overrides the name from the code object.
The optional argdefs tuple specifies the default argument values.
The optional closure tuple supplies the bindings for free variables.

In your case we can reuse the closure just like the code:

>>> def outer(fn):
...     def inner(x, y): return x + fn(x, y)
...     return function(inner.func_code, {}, closure=inner.func_closure)
...
>>> outer(lambda a, b: a*b)(2, 3)
8

While we're at it, let's explore the remaining arguments:

>>> f = outer(lambda a, b: a*b)
>>> g = function(f.func_code, {}, "yadda", (10, 20), f.func_closure)
>>> g
<function yadda at 0x2aba094e1050>
>>> g()
210

Peter




More information about the Python-list mailing list