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

Bengt Richter bokr at oz.net
Mon Jan 24 02:30:32 EST 2005


On Sun, 23 Jan 2005 13:14:10 -0700, Steven Bethard <steven.bethard at gmail.com> wrote:

>Bengt Richter wrote:
>> On Sat, 22 Jan 2005 16:22:33 +1000, Nick Coghlan <ncoghlan at iinet.net.au> wrote:
>> 
>> 
[Steven Bethard]
>>>> > If you really want locals that don't contribute to arguments, I'd be
>>>> > much happier with something like a decorator, e.g.[1]:
>>>> >
>>>> > @with_consts(i=1, deftime=time.ctime())
>>>> > def foo(x, y=123, *args, **kw):
>>>> >    return x*y, kw.get('which_time')=='now' and time.ctime() or deftime
>>>> >
>>>> > Then you don't have to mix parameter declarations with locals
>>>> > definitions.
[...]

[Nick Coghlan]
>>>Raymond's constant binding decorator is probably a good model for how to do it:
>>>http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940
>>>
>> 
>>
[Bengt Richter] 
>> I thought so too. I modified it to accept **presets as a keyword argument
>> and generate constants and assignments from its values matching assignment names
>> when the rhs was __frompresets__, e.g.,
>> 
>>  >>> from makeconstpre import make_constants as pre
>>  >>> import time
>>  >>> @pre(verbose=True, deftime=time.ctime(), a=1, b=2, c=3, pi=__import__('math').pi)
>>  ... def foo():
>>  ...     deftime = __frompresets__
>>  ...     b, a = __frompresets__
>>  ...     c = __frompresets__
>>  ...     pi = __frompresets__
>>  ...     return locals()
>>  ...
>>  __frompresets__ : deftime --> Sat Jan 22 20:18:09 2005
>>  __frompresets__ : ('b', 'a') --> (2, 1)
>>  __frompresets__ : c --> 3
>>  __frompresets__ : pi --> 3.14159265359
>>  locals --> <built-in function locals>
>
[Steven Bethard]
>Hmm... Having to state
>     deftime = __frompresets__
>when you've already stated
>     deftime=time.ctime()
>seems a little redundant to me...
>
Yeah, but as a quick hack, it made the byte code twiddling all changing byte codes in-place.
I didn't want to verify that byte code wouldn't need relocation fixups if I inserted something,
(unless of course within a suite with branches or loops) but hopefully it's easily so at the
beginning.

BTW, unlike default arguments, varname = __frompresets__ will work anywhere in the code,
(for the current decorator version) and the generated byte code will have a load of
an appropriate constant (the same one if the same name is being assigned). This would
be tricky to get right if done in a hidden just-in-time manner only in branches that
used the values, but hidden initialization of the whole presets set at the beginning
should be relatively easy if there are no relocation problems.
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.

Regards,
Bengt Richter



More information about the Python-list mailing list