Luis Alberto Zarrabeitia Gomez <ky...@uh.cu> writes: > A bit offtopic: a while ago I think I saw a recipe for a decorator > that, via bytecode hacks, would bind otherwise global names to the > local namespace of the function. Can anyone remember it/point me to > it? An @bind decorator that would 'localize' all the global names, > including the still unexistent but already know function name, would > guarantee that at least recursion calls the same function instead of > "whatever happens to be bound to their name at runtime". If it wasn't > a hack, anyway.
I remember a discussion on python-ideas, and I wrote this decorator at the time: def new_closure(vals): args = ','.join('x%i' % i for i in range(len(vals))) f = eval("lambda %s:lambda:(%s)" % (args, args)) return f(*vals).func_closure def localize(f): f_globals = dict((n, f.func_globals[n]) for n in f.func_code.co_names) f_closure = ( f.func_closure and new_closure([c.cell_contents for c in f.func_closure]) ) return type(f)(f.func_code, f_globals, f.func_name, f.func_defaults, f_closure) Unfortunately it fails for recursive functions: >>> @localize ... def fac(n): ... return 1 if n <= 1 else n*fac(n - 1) ... Traceback (most recent call last): File "<stdin>", line 1, in <module> File "localize.py", line 7, in localize f_globals = dict((n, f.func_globals[n]) for n in f.func_code.co_names) File "localize.py", line 7, in <genexpr> f_globals = dict((n, f.func_globals[n]) for n in f.func_code.co_names) KeyError: 'fac' It can be fixed, but not very easily precisely because the function is recursive. I've hacked a quick way to do it below. def reclocalize(f): def wrapper(*args, **kwargs): return recf(*args, **kwargs) def getglobal(name): return wrapper if name == f.__name__ else f.func_globals[name] f_globals = dict((n, getglobal(n)) for n in f.func_code.co_names) f_closure = ( f.func_closure and new_closure([c.cell_contents for c in f.func_closure]) ) recf = type(f)(f.func_code, f_globals, f.func_name, f.func_defaults, f_closure) return wrapper Now it works as intended: >>> @reclocalize ... def fac(n): ... return 1 if n <= 1 else n*fac(n - 1) ... >>> fac(10) 3628800 >>> foo = fac >>> del fac >>> foo(10) 3628800 -- Arnaud -- http://mail.python.org/mailman/listinfo/python-list