On Fri, Apr 13, 2018 at 09:56:35PM +1000, Chris Angelico wrote:
> How many times have people asked for "with (expr as name):" to > be supported, allowing the statement to spread over multiple lines? > With this syntax, it would suddenly be permitted - with dangerously > similar semantics. I see your point, but why don't we support "with (expr as name):" to allow multiple lines? No, don't answer that... its off-topic. Forget I asked. In any case, we already allow similar syntax with different meaning in different places, for example, something that looks just like assignment inside expressions: functions = [len, ord, map, lambda x, y=1: x+y] But its not really an assignment as such, its a parameter declaration. If we agree that the benefit of putting the expression first is sufficiently large, or that the general Pythonic look of "expr as name" is sufficiently desirable (it just looks and reads nicely), then we can afford certain compromises. Namely, we can rule that: except expr as name: with expr as name: continue to have the same meaning that they have now and never mean assignment expressions. Adding parens should not change that. If you try to write something like: except (spam or eggs as cheese) or function(cheese) as name: with (spam or eggs as cheese) or function(cheese) as name: etc (or any other assignment expression, effectively anything which isn't currently allowed) then you get a syntax error. So this: with expr as name: process(name) will only work if expr returns an object with a context manager. But that's they way it works now, so nothing really changes. In other words, the rule is that "expr as name" keeps its current, older semantics in with and except statements, and NEVER means the new, PEP 572 assignment expression. Yes, that's a special case that breaks the rules, and I accept that it is a point against "as". But the Zen is a guideline, not a law of physics, and I think the benefits of "as" are sufficient that even losing a point it still wins. > For many MANY context managers, "with (expr as > name):" would do the exact same thing as "with expr as name:". There > is a general expectation that adding parentheses to an expression > usually doesn't change the behaviour, and if it's legal, people will > assume that the behaviour is the same. It isn't, and it's such a > sneaky difference that I would call it a bug magnet. Indeed. I wouldn't allow such a subtle difference in behaviour due to parens. That reminds me of the Python 1 and early 2.x except clauses, where except ValueError, TypeError: except (ValueError, TypeError): meant different things. I still shudder at that one. > So if it's a bug magnet, what do we do? > > 1) Permit the subtly different semantics, and tell people to be careful No. > 2) Forbid any use of "(expr as name)" in the header of a 'with' statement You can't forbid it, because it is currently allowed syntax (albeit currently without the parens). So the rule is, it is allowed, but it means what it meant pre-PEP 572. > 3) Forbid it at top level, but permit it deeper down I don't know what that means. But whatever it means, probably no :-) > 4) Something else?? Well, there's always the hypothetical -> arrow binding operator, or the Pascal := assignment operator (the current preference). I don't hate the := choice, I just think it is more Pascal-esque that Pythonic :-) > > I don't especially dislike := but I really think that putting the > > expression first is a BIG win for readability. If that requires parens > > to disambiguate it, so be it. > > There's a mild parallel between "(expr as name)" and other uses of > 'as', which bind to that name. Every other use of 'as' is part of a > special syntactic form ('import', 'with', and 'except'), but they do > all bind to that name. (Point of interest: You can "with expr as > x[0]:" but none of the other forms allow anything other than a simple > name.) I disagree: I think it is a strong parallel. They're both name bindings. How much stronger do you want? True, we don't currently allow such things as import math as maths, mathematics, spam.modules[0] but we could if we wanted to and there was a sensible use-case for it. > There's a strong parallel between "target := value" and "target > = value"; Sure. And for a statement, either form would be fine. I just think that in an expression, it is important enough to bring the expression to the front, even if it requires compromise elsewhere. [...] > I actually can't find anything about the -> operator, only the <- one. > (Not that I looked very hard.) Is it a truly viable competitor, or > just one that you'd like to see mentioned for completeness? Yes, as I mentioned in another post, R allows both -> and <-, some language called BETA uses ->, various calculator BASICs use -> (albeit with a special single character, not a digraph) as does HP RPN. Here's an example from R: > c(1, 2, 3+4, 5) -> data > data [1] 1 2 7 5 But whether it is viable or not depends on *us*, not what other languages do. No other language choose the syntax of ternary if expression before Python used it. We aren't limited to only using syntax some other language used first. > > I think that there should be more attention paid to the idea of putting > > the expression first, rather than the name. > > How many ways are there to bind a value to a name? [...] > I'm seeing consistency here in that *EVERY* name binding where the > name is at the end uses "as target" as its syntax. Everything else > starts with the target, then defines what's being assigned to it. So I > don't see much value in a "->" operator, except for the mere fact that > it's different (and thus won't conflict in except/with); and the bulk > of name bindings in Python put the name first. We shouldn't be choosing syntax because other syntax does the same. We should pick the syntax which is most readable and avoids the most problems. That's why Guido bucked the trends of half a century of programming languages, dozens of modern languages, and everything else in Python, to put the conditional in the middle of ternary if instead of the beginning or end. (And he was right to do so -- I like Python's ternary operator, even if other people think it is weird.) If people agree with me that it is important to put the expression first rather than the target name, then the fact that statements and for loops put the name first shouldn't matter. And if they don't, then I'm outvoted :-) -- 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/