[Python-ideas] 'Injecting' objects as function-local constants

Alex Light scialexlight at gmail.com
Tue Jun 14 19:44:26 CEST 2011


On Mon, Jun 13, 2011 at 9:12 PM, Jan Kaliszewski <zuo at 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20110614/e07b8028/attachment.html>


More information about the Python-ideas mailing list