syntax for preset locals without using dummy args with defaults

Bengt Richter bokr at oz.net
Wed Jan 15 17:25:31 EST 2003


On Wed, 15 Jan 2003 10:00:56 +0200 (IST), Beni Cherniavsky <cben at techunix.technion.ac.il> wrote:

>On 2003-01-14, Andrew McGregor wrote:
>
>> How about:
>>
>> with:
>>   z = some_expression
>>   z1 = some_other_expression
>>   # for consistency, should allow this too.
>>   def quux(bar):
>>       do_something()
>> do:
>>   def foo(x, y=default):
>>       do_stuff()
>>
>Yes, this is probably optimal (or very close) if we want it at all.
>
I have a couple of reservations: 1) I think already the distinction between
what I have been calling "def-time" and "call-time" is often missed (i.e.,
def ... defines executable code that builds the executable function whose
code later gets executed when it is called, and thus there are two distinct
execution times and codes involved), and the above doesn't make it plain
unless you already know.

The keywords "with" and "do" in the above don't strongly suggest what is
supposed to happen IMO, especially since "with" carries a Pascal meaning.

Also, what is the scope and environment of the "do"? I.e., what would
other statements in the do: suite mean if they appeared before or after
the def?

It is crucial to the semantics that it be understood that the expressions in
the suite of the "with" are only executed once, yet the bindings are copied
each time the function is called, to preset the local bindings afresh.
IOW, the effect is something[1] like:

    def _presets():
        z = some_expression
        z1 = some_other_expression
        # for consistency, should allow this too.
        def quux(bar):
            do_something()
        return vars() # capture and return the bindings of interst
    _presets = _presets() # (the function gets one-time use)

    def foo(x, y=default):
         vars().update(_presets) # hidden part of locals setup
         do_stuff()

[1] If you actually try this, you will run into the difference between
locals created as such in collecting assigned-to variables in the function
body, vs bindings that can be created dynamically beyond those, as with
the update. E.g., if you pass vars() to do_stuff(), the latter will see
all the bindings, but if you try to access a local variable that hasn't
been assigned, you'll get an undefined global (unless there happens to
be a global with that name of course). I.e., the two kinds of bindings
don't work that great together, ISTM. But that's another discussion.

But the functionality is close enough to suggest passing a dict somehow
to def as an initializer. And the _presets() trick above suggests an
alternate spelling for a dictionary literal, which might by default imply
an underlying implementation like a function local namespace (imagining
a fast implementation where its representation could be memcopied like
a C struct for purposes of initializing function locals before parameter
bindings are superimposed). Such a dictionary literal might be written like:

    _presets = {:
        z = some_expression
        z1 = some_other_expression
        # for consistency, should allow this too.
        def quux(bar):
            do_something()

(where there is no closing ':}' but instead '{:' introduces a suite, and the
dict value consists in the bindings created therein).


Then if you could pass a dict as an initializer to def, you could write, e.g.,

    def(_presets) foo(x, y=default):
         do_stuff()

Sort of like passing base classes, but a bit different ;-)


BTW, the other thing the above doesn't address is persistence of bindings
(analogous to C static variables containing pointers the still point
as before on the next call).

If there were something analogous to base classes and __metaclass__ for
functions, it might be interesting...

Regards,
Bengt Richter




More information about the Python-list mailing list