On Sun, May 19, 2019 at 11:46 AM David Mertz <mertz@gnosis.cx> wrote:
I think you probably mean something other than what you actually write. It doesn't really make sense for "any expression" as far as I can tell. What would it possibly mean to write:
with (2+2) as foo: print(foo)
I have occasionally thought it would be nice to do something like this (and I could, but I haven't, so I guess I don't think it that strongly):
@contextmanager ... def bind(val): ... yield val ... with bind(2+2) as four: ... print(four) ... 4
Thing is, this is slightly deceptive. People will assume/expect that the name binding 'four' ends at the end of the 'with' block. In actual fact, something like this has an entrance but no exit - there is absolutely no meaning to the unindent. Functionality would be identical to "with bind(2+2) as four: pass" followed by the same code. Python's 'with' block guards a section of code. At the end of that code, something has to get undone - a file gets closed, a database transaction gets committed/rolled back, a suppressed exception returns to normal state, etc. You can't have the __exit__ method do "del four", so with current code, there's no code-significant meaning to this block. So there are two broad options: 1) Keep it having no functional meaning, just a semantic declaration "hey, this is the only place I'm using this". Not hugely valuable, but maybe people would like it. Probably best to have the three-line bind() function. 2) Redefine the 'with' block or create a new syntactic form such that the variable actually creates a subscope. That way, at the end of the block, the name would revert to its former meaning. x = 1 with local 2 as x: print(x) # 2 print(x) # 1 This would have definite value, but would be a much larger change to the language. And variants of it have been proposed and rejected before. ChrisA