
Nick Coghlan wrote:
On Fri, Jun 17, 2011 at 3:15 AM, Jan Kaliszewski <zuo@chopin.edu.pl> wrote:
or even (to stress that it is a language syntax construct:
@inject mem=collections.Counter(), MAX_MEM=1000 def do_and_remember(val, verbose=False):
While that would require the from__future__ dance to make "inject" a new keyword, I like it much better than the looks-like-a-decorator-but-isn't syntax.
What benefit is there in making inject a keyword? Even super isn't a keyword. As far as I'm concerned, inject need only be a function in the functools module, not even a built-in, let alone a keyword. Here's a quick and dirty version that comes close to the spirit of inject, as I see it. Thanks to Alex Light's earlier version. # Credit to Alex Light. from contextlib import contextmanager from functools import wraps def inject(**localArgs): def decorator(func): glbs = func.__globals__ @wraps(func) def inner(*args, **kwargs): with _modifyGlobals(glbs, localArgs): ret = func(*args, **kwargs) return ret return inner return decorator @contextmanager def _modifyGlobals(glbls, additions): frmglbls = glbls.copy() try: glbls.update(additions) yield finally: glbls.clear() glbls.update(frmglbls) And demonstrating it in use:
def func(obj): ... print(len) ... return len(obj)+1 ... import builtins newfunc = inject(len=lambda o: print(o) or builtins.len(o))(func)
func([]) # Original function unchanged, still uses uninjected len. <built-in function len> 1 newfunc([]) # New function uses injected len. <function <lambda> at 0xb7c2f86c> [] 1
And as a decorator:
@inject(a=1) ... def spam(): ... print(a) ... a = 42 spam() 1
Unfortunately, this proof-of-concept inject function doesn't actually inject into locals, hence the "import builtins" work-around. But it demonstrates the intent, and the API. -- Steven