Problem with Lexical Scope

Bengt Richter bokr at oz.net
Sat Dec 17 11:53:07 CET 2005


On 17 Dec 2005 01:16:31 -0800, "jslowery at gmail.com" <jslowery at gmail.com> wrote:

>>>from functional import curry
>
>>I'm not familiar with that module, but I wrote a byte-code-munging curry
>>as a decorator that actually modified the decorated function to eliminate
>>parameter(s) from the signature and preset the parameter values inside the code.
>>I mention this because pure-python currying that I've seen typically creates a wrapper
>>function that calls the original function, and slows things down with the extra calling
>>instead of speeding things up, at least until some future version of python.
>>Looks nice on the surface though.
>
>Sounds very useful. Is this open source? All of the curry functions
>I've seen in the wild use a wrapper as well. I don't care for this
>either mainly because it hides away the function attributes and when I
>use decorators on functions that mudge attributes, it doesn't work.
>
The curry part works like:
(first unmodified)

 >>> import inspect
 >>> def foo(x, y): return x*y
 ...
 >>> import dis
 >>> dis.dis(foo)
   1           0 LOAD_FAST                0 (x)
               3 LOAD_FAST                1 (y)
               6 BINARY_MULTIPLY
               7 RETURN_VALUE
 >>> inspect.getargspec(foo)
 (['x', 'y'], None, None, None)

(modified)
 >>> from ut.presets import presets, curry
 >>> @curry(y=111)
 ... def foo(x, y): return x*y
 ...
 >>> dis.dis(foo)
   1           0 LOAD_CONST               1 (111)
               3 STORE_FAST               1 (y)

   3           6 LOAD_FAST                0 (x)
               9 LOAD_FAST                1 (y)
              12 BINARY_MULTIPLY
              13 RETURN_VALUE
 >>> inspect.getargspec(foo)
 (['x'], None, None, None)

The presets decorator does the same except doesn't modify the signature
(it came first ;-)

 >>> def foo():
 ...     return now()
 ...
 >>> dis.dis(foo)
   2           0 LOAD_GLOBAL              0 (now)
               3 CALL_FUNCTION            0
               6 RETURN_VALUE
 >>> import time
 >>> @presets(now=time.ctime)
 ... def foo():
 ...     return now()
 ...
 >>> dis.dis(foo)
   1           0 LOAD_CONST               1 (<built-in function ctime>)
               3 STORE_FAST               0 (now)

   3           6 LOAD_FAST                0 (now)
               9 CALL_FUNCTION            0
              12 RETURN_VALUE
 >>> foo()
 'Sat Dec 17 02:49:06 2005'

Humph. Good night ;-/

I googled and found a post of mine, which I think may be my last version, at 

    http://groups.google.com/group/comp.lang.python/msg/7d27a53385e89924

where you can look to see if it's interesting. I think it's probably more fruitful
to put work into doing it by way of rewriting the AST, which would potentially
allow folding constant expressions that may be formed when parameters
become constants, etc. So I haven't pursued byte code munging much further.
The version above only had minor testing, and only on python 2.4. IOW, basically
a proof of concept.

I based my presets/curry decorator on the pattern of a decorator Raymond Hettinger wrote,
which optimizes global accesses and other stuff. No warranties, mind! ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list