On Fri, 14 Jan 2005 01:48:48 +1000, Nick Coghlan <[EMAIL PROTECTED]> wrote:
>Nick Coghlan wrote: >> Semantics >> --------- >> The code:: >> >> <statement> with: >> <suite> >> >> translates to:: >> >> def unique_name(): >> <suite> >> <statement> >> unique_name() > >I've come to the conclusion that these semantics aren't what I would expect >from >the construct. Exactly what I would expect can't really be expressed in >current >Python due to the way local name bindings work. The main thing to consider is >what one would expect the following to print: > >def f(): > a = 1 > b = 2 > print 1, locals() > print 3, locals() using: > a = 2 > c = 3 > print 2, locals() > print 4, locals() > >I think the least suprising result would be: > >1 {'a': 1, 'b': 2} # Outer scope >2 {'a': 2, 'c': 3} # Inner scope >3 {'a': 2, 'b': 2, 'c': 3} # Bridging scope >4 {'a': 1, 'b': 2} # Outer scope > >In that arrangement, the statement with a using clause is executed normally in >the outer scope, but with the ability to see additional names in its local >namespace. If this can be arranged, then name binding in the statement with >the >using clause will work as we want it to. > >Anyway, I think further investigation of the idea is dependent on a closer >look >at the feasibility of actually implementing it. Given that it isn't as >compatible with the existing nested scope structure as I first thought, I >suspect it will be both tricky to implement, and hard to sell to the BDFL >afterwards :( > In the timbot's let/in format: def f(): a = 1 b = 2 print 1, locals() let: a = 2 c = 3 print 2, locals() in: print 3, locals() print 4, locals() I think the effect would be as if >>> def f(): ... a = 1 ... b = 2 ... print 1, locals() ... def __unique_temp(): ... a = 2 ... c = 3 ... print 2, locals() ... def __unique_too(): ... print 3, locals() ... __unique_too() ... __unique_temp() ... del __unique_temp ... print 4, locals() ... >>> f() 1 {'a': 1, 'b': 2} 2 {'a': 2, 'c': 3} 3 {} 4 {'a': 1, 'b': 2} print 3, locals() doesn't show a,b,c in locals() unless you use them somehow in that scope, e.g., >>> def f(): ... a = 1 ... b = 2 ... print 1, locals() ... def __unique_temp(): ... a = 2 ... c = 3 ... print 2, locals() ... def __unique_too(): ... print 3, locals(), (a,b,c) # force references for locals() ... __unique_too() ... __unique_temp() ... del __unique_temp ... print 4, locals() ... >>> f() 1 {'a': 1, 'b': 2} 2 {'a': 2, 'c': 3, 'b': 2} 3 {'a': 2, 'c': 3, 'b': 2} (2, 2, 3) 4 {'a': 1, 'b': 2} Of course, locals() does not include globals, even though they're referenced and visible: >>> b 'global b' >>> def bar(): ... print locals(), b ... >>> bar() {} global b The trouble with this is that bindings created in __unique_too all get thrown away, and you wouldn't want that limitation. So I proposed specifying the (re)bindable names in a parenthesized list with the let, like "let(k, q, w): ..." so that those names would be (re)bindable in the same scope as the let(...): statement. As an extension, I also proposed optionally binding __unique_temp to a specified name and not calling it automatically, instead of the automatic call and del. That provides new ways to factor updates to local namespaces into local functions with selective write-through (bind/rebind) to local names. E.g., # define case blocks for switch # better sugar later, this is to demo functinality ;-) #a let(x): k = 123 in foo: x = k #b let(x, y): q = 456 from math import pi as r in bar: x = q y=r # extra binding created if bar is called #c let(x):in baz:x=789 # most compact form, where nothing in the let clause switch = dict(a=foo, b=bar, c=baz) Now you can update local bindings with a case switch: x = 0 case = 'b' print x # => 0 switch[case]() # executes bar() in this example, which assigns local x=456 and y=pi print x # => 456 This spare example is easy to dismiss, but think of foo, bar, and baz as arbitrary sequences of statements in the local namespace, except you can factor them out as a single named group and invoke them safely by name(), and have them affect only the local names you specify in the group's let(x, y, ...): spec. It provides a new way of factoring. As well as things no one has thought of yet ;-) The other thing to think about is that the let suite could be strictly def-time, which would provide the opportunity to avoid re-calculating things in functions without abusing default args, and using the easy closure-variable creation instead. E.g., let(foo): preset = big_calc() in: def foo(x): return x * preset (This "in:" has no "in xxx:" name, so the effect is immediate execution of the anonymously defined function, which writes through to foo with the def, as permitted by let(foo):). Problems? (Besides NIH, which I struggle with regularly, and had to overcome to accept Tim's starting point in this ;-) Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list