We have where syntax in combination with suite expression syntax (bear with me, I think a good synergy will emerge ;-)
http://groups.google.co.uk/groups?selm=mailman.403.1105274631.22381.python-list%40python.org http://groups.google.co.uk/groups?selm=3480qqF46jprlU1%40individual.net are the key referneces for background (I'm just repeating from Oren's post for convenience). The first suggests a grammar mod for its proposed "with" (rather than the name "where"), but it doesn't cover the variations we are discussing now. If "where" is not a good word, and "with" is destined for use that may clash, how about "letting" or if that's too long, "per" ? Anyway, the new stuff adds the new compound statements Here's a cut at Grammar modifications: (though I guess the grammar in http://www.python.org/doc/current/ref/grammar.txt is really closer to actual parsing. BTW, how is the Grammar file that comes with the sources maintained along with the former? E.g., I didn't see how the latter parses a non-assignment expression as a statement, e.g. NAME '(' ')' Maybe I have a glitched version of Grammar? But anyway, since I did this already, it will serve as a sketch: compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef | letting_stmt | named_suite_stmt small_stmt: tiny_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt tiny_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | import_stmt | assert_stmt letting_stmt: tiny_stmt 'letting' ( let_stmt | ':' suite ) let_stmt: named_suite_stmt | assignments_stmt assignments_stmt: expr_stmt?? named_suite_stmt: NAME suite_expr suite_expr: '::' suite | parameters ':' suite | 'def' parameters ':' suite I split out a tiny_stmt subset of small_stmt so we won't accept "continue letting x=5" and such. Basically we have either <tiny_stmt> letting: <suite> # meaning any possible suite, but obviously should concern itself # with binding names for tiny_stmt to use or <tiny_stmt> letting <let_stmt> where <let_stmt> binds names by assignment, or by a named_suite_stmt, e.g, (assuming a bare expression is parsed as an expr_stmt) foo(x) letting x=1 # simple let_stmt as assignmerns_stmt foo(x, y) letting x,y = 1,2 # assignments_stmt should exclude augassign operators so is not == safe_open(tk, 'data.txt') letting tk(f): # this suite is thunk tk's body, called back by foo, passing safely opened f as arg longest = max(len(line) for line in f) # save result longest in local namespace If you put the ':' after letting, you introduce a general suite whose bindings will override any name bindings otherwise used by the preceding tiny_stmt, e.g, the above in letting: form foo(x) letting: x=1 # simple let_stmt as assignmerns_stmt foo(x, y) letting: x,y = 1,2 # assignments_stmt should exclude augassign operators so is not == safe_open(tk, 'data.txt') letting: tk(f): # this suite is thunk tk's body, called back by foo, passing safely opened f as arg longest = max(len(line) for line in f) # save result longest in local namespace Note that tk(f): and its suite work just like a def, except for binding a thunk instead. You can also bind tk to the thunk expression, analogous to binding a lambda to what a def name would bind, e.g., This is will do the same as above, though the isolated (f): may look unfamiliar, ;-) safe_open(tk, 'data.txt') letting: tk = (f): # this suite is thunk tk's body, called back by foo, passing safely opened f as arg longest = max(len(line) for line in f) # save result longest in local namespace Since letting: introduces a full-fledged suite, nested lettings of both kinds become possible, e.g. foo(tk, func, *args, **kw) letting: kw = dict(tuplist) letting: tuplist = [(1,'one'), (2,'two')] # silly example args = d.values() letting d:: # d becomes dict of suite bindings a = 123 def foo(x): tk(logitem): # tk becomes thunk with body defined in following suite print logitem def func(x, y): # func is ordinary but transient function return 'Hi from fun with', (x,y) What I haven't covered is the same-indentation aligned 'with' following a statement, as seems permitted in Nick reference post where he says """ Grammar Change -------------- Current:: statement ::= stmt_list NEWLINE | compound_stmt New:: statement ::= (stmt_list NEWLINE | compound_stmt) [local_namespace] local_namespace ::= "with" ":" suite """ I'll have to leave that for now. Anyway, hope this all evolves into something neat ;-) Actually, I don't like "letting" that much as the word. I keep having to type where^H^H^H^H^Hletting ;-) "per" would be short, but maybe not mnemonic enough. "with" might be good, but I am allowing with not to have a colon, e.g. with a single thunk definition for a function call: final_status = safe_open(tk, 'data.txt') with tk(f): longest = max(len(line) for line in f) Since my 'letting' is effectively a tiny_stmt trailer and anticipated with usage is more header like, maybe that is enough to disambiguate. I'll have to see the future with grammar. Hm, Let's see if Nick Coghlan's summary of examples can be handled with letting: Examples -------- # Statement local functions (from Andrey Tatarinov) # aka How to cope if lambda goes away :) res = [ f(i) for i in objects ] with: def f(x): #do something OK as is. # Declaring properties (from Nick Coghlan) class C(object): x = property(get, set) with: def get(self): pass def set(self, value): pass OK as is. # Design by contract (from Nick Coghlan) @dbc(pre, post) def foo(): pass with: def pre(): pass def post(): pass Problem, but if decorator expressions were allowed to have letting, @dbc(pre, post) letting: def pre(): pass def post(): pass def foo(): pass # Singleton classes (from Paul Rubin) C = C() with: class C: pass OK as is. # Complex default values (from Carlos Ribeiro) def f(x=default()): pass with: def default(): pass Since this is not decorated, I can do it with an anonymous def suite expression which, being an expression (making the whole a simple expr assignment) allows letting: f = def(x=default()): pass letting: # dedent to this line ends anonymous def suite and goes back to expression context def default(): pass To show the expression nature better, (not that it's a preferred spelling ;-), the expression is parenthesized, and closes with the closing ')' f = (def(x=default()): pass ) letting: def default(): pass or uglier: f = (def(x=default()): pass) letting: def default(): pass You could even write a one-liner for this, since the suites are one-liner passes ;-) f = (def(x=default()):pass) letting default=(def():pass) So there was really only a problem with the decorator. But I gotta go for now. Regards, Bengt Richter -- http://mail.python.org/mailman/listinfo/python-list