specifying constants for a function (WAS: generator expressions: performance anomaly?)

Bengt Richter bokr at oz.net
Tue Jan 25 04:18:38 EST 2005


On Mon, 24 Jan 2005 20:35:09 GMT, bokr at oz.net (Bengt Richter) wrote:

>On Mon, 24 Jan 2005 00:31:17 -0700, Steven Bethard <steven.bethard at gmail.com> wrote:
>
>>Bengt Richter wrote:
>>> So, e.g., for
>>> 
>>>  >>> presets = dict(a=1, b=2, deftime=__import__('time').ctime())
>>> 
>>> in the decorator args, the next version will act as if the decorated
>>> function had the source code
>>> 
>>>  >>> print '%s = __frompresets__' % ', '.join(sorted(presets))
>>>  a, b, deftime = __frompresets__
>>> 
>>> for the current version, except that it will be hidden.
>>
>>Cool!  Keep us posted.  I assume you'll put this into the Cookbook?
>>
>Not ready for prime time, I guess, but I made a module that does presets
>and also adjusts parameters and count to do currying without nested function
>calling in the curried function.
>
> >>> from presets import presets, curry
> >>> @presets(verbose=True, a=1, b=2, deftime=__import__('time').ctime())
> ... def foo():
> ...    print (a, b)
> ...    print deftime
> ...
>
> presets: -- "name(?)" means name may be unused
>            a = 1
>            b = 2
>      deftime = 'Mon Jan 24 12:16:07 2005'
>
> >>> foo()
> (1, 2)
> Mon Jan 24 12:16:07 2005
> >>> @curry(verbose=True, y=444)
> ... def bar(x=3, y=4):
> ...     return x*y
> ...
>
> presets: -- "name(?)" means name may be unused
>            y = 444
>
> >>> bar(2)
> 888
> >>> bar(2, 3)
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: bar() takes at most 1 argument (2 given)
> >>> bar()
> 1332

Not much reaction, so I guess I won't see it if any, since I am going off line for a while.
BTW, this exercise makes me realize that you could do some other interesting things too,
if you put your mind to it. E.g., it might be interesting to inject properties into
the local namespace of a function, so that e.g., x=1 would would trigger an effect
like someobj.x = 1, where type(someobj).x was a property. It wouldn't be
too hard to make

    @addprop(verbose=True, x=property(getx, setx, delx))
    def foo():
        x = 123
        return x

etc. Maybe could be used to monitor access to specific locals for debug,
or other uses. Haven't even begun to think about that. 

Another thing is to turn selected local defs into constants, since executing
the aggregation-of-parts code that accomplished the def may well be unchanging.
This would reduce the execution cost of nested functions. I guess that is
a specific case of a more general sticky-evaluate-rhs-once kind of directive
for locals that are only assigned in one place. special sentinels could
be used in the decorator keyword values to indicate this treatment of the
associated name, e.g.
    from presets import presets
    @presets(x=presets.STICKY, y=123)
    def foo(y):
        x = initx() # done once on the first call, making x references constant after that
        return x*y

Another thing that could be done is to inject pre and post things like atexit stuff.
Also maybe some adaptation things that is just a buzzword so far that I haven't explored.

BTW, is there another op that needs relocation besides JUMP_ABSOLUTE? 

I was wondering about doing code mods by messing with an ast, but a decorator would
have to chase down the source and reparse I guess, in order to do that. It would be
interesting to be able to hook into ast stuff with some kind of metacompile hook (hand waving ;-)

Bye for a while.

Regards,
Bengt Richter



More information about the Python-list mailing list