I
Ian Kelly
So there should be a way to replace the closure of a function with a
snapshot of it at a certain time. If there was an internal function with
access to the readonly attribute func_closure and with the capability of
changing or creating a cell object and thus hbeing capable of doing so, it
could be used a a decorator for a function to be "closure-snapshotted".
So in
funcs=[]
for i in range(100):
@closure_snapshot
def f(): return i
funcs.append(f)
each f's closure content cells would just be changed not to point to the
given variables, but to a cell referenced nowhere else and initialized with
the reference pointed to by the original cells at the given time.
For CPython 3.2:
import functools
import types
def makecell(value):
def f():
return value
return f.__closure__[0]
def closure_snapshot(f):
if f.__closure__:
snapshot = tuple(makecell(cell.cell_contents) for cell in f.__closure__)
else:
snapshot = f.__closure__
g = types.FunctionType(f.__code__, f.__globals__.copy(), f.__name__,
f.__defaults__, snapshot)
functools.update_wrapper(g, f, functools.WRAPPER_ASSIGNMENTS +
('__kwdefaults__',))
return g
.... @closure_snapshotfuncs = []
for i in range(10):
.... def f(): return i
.... funcs.append(f)
....
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][f() for f in funcs] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
funcs = [closure_snapshot(lambda: i) for i in range(10)]
[f() for f in funcs]
It doesn't really seem any more straightforward to me than the "i=i"
trick. Also, I don't know how portable this is to different Python
implementations or future versions. Finally, note that in order to
make this work correctly in all cases (such as the first example
above, where i is a global, not a cell) we have to snapshot the
globals as well, which could cause further confusion.
Cheers,
Ian