On Fri, Apr 13, 2018 at 05:04:00PM +0200, Jacco van Dorp wrote: > > I'm saying, don't even try to distinguish between the forms with or > > without parens. If we add parens: > > > > with (expr as name): > > > > it may or may not be allowed some time in the future (since it isn't > > allowed now, but there are many requests for it) but if it is allowed, > > it will still mean a context manager and not assignment expression. > > > > (In case it isn't obvious, I'm saying that we need not *require* parens > > for this feature, at least not if the only reason for doing so is to > > make the with/except case unambiguous.) > > > > So if I read this correctly, you're making an argument to ignore parens ?
You can always add unneeded parentheses for grouping that have no effect: py> value = ((((( 1 )) + (((1)))))) py> value 2 One should never be penalised by the interpreter for unnecessary parentheses. If they do nothing, it shouldn't be an error. Do you really want an error just because you can't remember operator precendence? flag = (spam is None) or (len(spam) == 0) The parens are unnecessary, but I still want to write them. That shouldn't be an error. > If I'd type with (expr as name) as othername:, I'd expect the original value > of expr in my name and the context manager's __enter__ return value in > othername. I don't really see any ambiguity in that case. That case would be okay. But the ambiguity comes from this case: with expr as name: That could mean either of: 1. Assignment-as-expression, in which case <name> gets set to the value of <expression> and __enter__ is never called; 2. With-statement context manager, in which case <name> gets set to the value of <expression>.__enter__(). (This assumes that assignment-expressions don't require parens. For the case where they are required, see below.) That's a subtle but important difference, and it is especially awful because most of the time it *seems* to work. Until suddenly it doesn't. The problem is that the most common context manager objects return themselves from __enter__, so it doesn't matter whether <name> is set to <expression> or <expression>.__enter__(), the result will be the same. But some context managers don't work like that, and so your code will have a non-obvious bug just waiting to bite. How about if we require parentheses? That will mean that we treat these two statements as different: with expr as name: # 1 with (expr as name): # 2 Case #1 is of course the current syntax, and it is fine as it is. It is the second case that has problems. Suppose the expression is really long, as so you innocently intend to write: with (really long expression) as name: but you accidently put the closing parenthesis in the wrong place: with (really long expression as name): as is easy enough to do. And now you have a suble bug: name will no longer be set to the result of calling __enter__ as you expect. It is generally a bad idea to have the presence or absense of parentheses *alone* to make a semantic difference. With very few exceptions, it leads to problems. For example, if you remember except clauses back in the early versions of Python 2, or 1.5, you will remember the problems caused by treating: except NameError, ValueError: except (NameError, ValueError): as every-so-subtly different. If you don't remember Python that long ago, would you like to guess the difference? > Without parens -> old syntax + meaning > with parens -> bind expr to name, because that's what the parens say. It isn't the parentheses that cause the binding. It is the "as". So if you move a perfectly innocent assignment-expression into a with statement, the result will depend on whether or not it came with parentheses: # these do the same thing while expression as name: while (expression as name): # so do these result = [1, expression as name, name + 2] result = [1, (expression as name), name + 2] # but these are subtly different and will be a trap for the unwary with expression as name: # name is set to __enter__() with (expression as name): # name is not set to __enter__() Of course, we could insist that parens are ALWAYS required around assignment-expressions, but that will be annoying. -- Steve _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/