On Mon, Jun 13, 2011 at 9:12 PM, Jan Kaliszewski firstname.lastname@example.org wrote:
On second thought: no. I mean: no -- for a separate syntax construct with limited usage possibilities (see: cases mentioned by Steven); yes -- for language improvements that would make possible one of the solutions:
- A real decorator:
a) quasi-argument-locals-based (names could be used to read injected value and later could be rebound, like arguments);
Forgive me if im wrong but i believe that this is possible without any language changes using pure python.
this is my attempt at it:
from inspect import getfullargspec as argspec
def makeLocal(**localArgs): def decorator(func): if (_anyConflicts(func, localArgs)): raise Exception("abiguity in names")
def inner(*args, **kwargs): if (any(Larg in kwargs.keys() for Larg in localArgs.keys())): raise NameError("no resetting locals") ## used to restore __globals__ i think this is alright since ## iirc __globals__ only holds references anyway frmglobals = func.__globals__.copy() func.__globals__.update(localArgs) ret= func(*args, **kwargs) func.__globals__.clear() func.__globals__.update(frmglobals) return ret inner.__doc__=func.__doc__ inner.__name__=func.__name__ return inner
def _anyConflicts(func, localArgs): fa = argspec(func) for Larg in localArgs: if (Larg in fa.args or Larg in fa.kwonlyargs or Larg in fa): return True return False
this uses a closure to hold the values of the injected values and hides them
all test pass exactly as if the values were defined with makeLocals were globals within the function but all act as if they are locals outside of it.
this means that if we define this this
@makeLocal(aList=list()) def add_and_print(arg): aList.append(arg) print(aList)
add_and_print(1) #it prints
if we try this
we get a NameError
and if we try this
all problems with global values still apply with this however. for example just as
anInt=33 def increment(): anInt+=1 foo(22)
throws a UnboundLocalError so does
@makeLocal(anInt=33) def increment(): anInt+=1
so what do you think?