On Mon, Jun 13, 2011 at 9:12 PM, Jan Kaliszewski <zuo@chopin.edu.pl> 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:

1. 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
>>>    return decorator
>>>
>>>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)

and run
>>>add_and_print(1) #it prints
[1]
>>>add_and_print(33) #prints
[1,33]

if we try this
>>>print(aList)
we get a NameError

and if we try this

>>>aList=['this','is','a','different','list']
>>>add_and_print(66)#prints
[1,33,66]
>>>print(aList)
['this','is','a','different','list']

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?

--Alex