
Hi all, Often I have typed something like for x in range(100) if is_prime(x): # do things with x to find that this does not work, instead resorting to: for x in range(100): if is_prime(x): # do things with x or for x in range(100): if not is_prime(x): continue # do things with x Other solutions to another case of this 'problem' are discussed has been discussed on StackOverflow ( http://stackoverflow.com/questions/6981717/pythonic-way-to-combine-for-loop-...) where it is suggested one uses a generator expression before the loop. None of these solutions seem very Pythonic to me. I appreciate there is a cost associated with changing the language syntax, and I do not understand all the finer details of the inner workings involved with the Python language development, however in my limited understanding in it would be: - fully backwards compatible, - require one to change "expression_list" to "or_test [comp_iter]" in the syntax of the for statement (if I got it right). - it would mean there is a Pythonic solution to a current 'problem' that does not have one. A few problems I foresee: - One wants for loops to bleed their target_list (that is the point normally), so this is different from generators, - This allows for nesting of generators, like in a generator expression which might be hard to implement? Note that this has been suggested before at least once ( https://mail.python.org/pipermail/python-dev/2007-November/075257.html), and that thread itself suggests it has been suggested before and shutdown by Guido (though no source is given for this). All the best, Henk-Jaap Wagenaar

On 23 February 2017 at 13:37, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
Thanks for your interest, but as you note this has already been proposed and rejected (from my personal recollection, more than once). So the key question is surely, what are you proposing that wasn't already discussed in previous threads, and why do you think that the new aspect of your proposal is likely to change Guido's mind? Sorry to be blunt, but rehashing an already extensively discussed idea isn't that productive for anyone. Paul

Just as a reference, I think the most recent reincarnation of this thread was: https://mail.python.org/pipermail/python-ideas/2016-September/042270.html On 23 February 2017 at 13:46, Paul Moore <p.f.moore@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager www.machinalis.com Skype: @dmoisset

Hi Paul, Daniel, others, That is fair enough and the right amount of blunt. Let me go through the points that were made in that thread (I have not found any other threads, if someone links to them, I will go through them as well): ----- From: https://mail.python.org/pipermail/python-dev/2007-November/075258.html, alternative solution (in current language):
for x in (x for x in range if is_prime(x)): # do something with x
This statement seems overly complicated for what it is trying to achieve and is semantically much harder to parse than the proposed alternative, e.g. there is repetition of the string "for x in". ---- A similar point to where I started from in https://mail.python.org/piperm ail/python-ideas/2016-September/042600.html:
---- The thread Daniel mentioned was ended by the following post https://mail.python.org/pipermail/python-ideas/2016-September/042285.html
I am not sure I agree with what he is saying (or I am not following it...). I think no-one in that thread particularly demonstrated why this could not supersede all equivalent solutions, even if the if is longer (but not complex), one can simply do: for x in range(10) \ if is_prime(x) and is_overabundant(x) and is_perfect(x) and x != 5: # do something with x where you would line up the if with the range/... on the previous line (this example is silly, because the conditions cannot be satisfied). This in my view would still be clearer and more concise than the alternative solutions. The emails in the threads seem to indicate that almost everyone is a shade of grey here, where some really like it (but can life without), some think it is alright but don't particularly mind, and some think it is not the worth the cost or would allow abuse. No-one seems to fundamentally hate the idea, or in a alternative world where it was already in Python, would suggest taking it out (even if it a backwards-incompatible epoch like 2->3 was approaching) though my reading between the lines of emails can be wrong. I think Erik's email (see above) shows this most clearly. In a straw poll at the company I work at everyone was in favour, though they obviously are not in charge of implementing or changing documentation so that is easy for them to say, they've got no skin in the game. I don't know whether it is common for such an idea to be brought up again and again by newcomers/those who don't strolls the archives enough, but if it keeps being brought up, and the main argument against is it would take time and effort to document and implement for little benefit, if Python sticks around for a long enough time, it will end up taking less time simply implement it! Best, Henk-Jaap On 23 February 2017 at 13:54, Daniel Moisset <dmoisset@machinalis.com> wrote:
On 23 February 2017 at 13:54, Daniel Moisset <dmoisset@machinalis.com> wrote:

On 23 February 2017 at 14:20, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
We really need a FAQ for this, if there isn't one already. You quoted Nick referring to a post I'd already made on this, and while I'm afraid I don't have time to find a link for you, I'll try to summarise again here. The bar for syntax changes to Python (and also library changes, although to a slightly lesser extent) is deliberately very high. This is not because people don't like proposals, but rather because the proposers consistently and drastically underestimate the cost of adding new features to the language. Things that need to be factored into the cost of a change: 1. Written materials, such as books, training courses, blog posts will be out of date, at best offering obsolete advice, at worst being outright wrong. Either the authors have extra work to do to change them, or the readers need to learn the "new truth", probably by making mistakes that they could have avoided if the material were correct. 2. Core developers need to understand the implementation of the new feature in order to support it. 3. Unintended consequences and/or problems with the design of the new feature (= bugs) need to be fixed. 4. People writing code that needs to support multiple versions of Python probably won't benefit, as they'll have to avoid the feature. But they will pay costs: a) They need to review that decision over time - is the new feature compelling enough that we should drop support for older versions yet? b) If there's an existing way of writing the construct, why ever change to the new version at all? c) PRs written by people used to the new feature will need reviewing and fixing for compatibility. 5. People not interested in the new feature will encounter it in other people's code and will need to understand it. 6. Someone has to code it. It's often not at all clear whether the proposer is offering to spend the time implementing the feature, and we typically don't bluntly say "well, will you write the code?" both because it's a bit aggressive, and also because an answer of "yes" isn't enough by itself - so we don't want to mislead people that the *only* problem is finding someone to code the change. There's probably others that I have missed. In addition, there's a couple of other points, not directly related to cost but still downsides of new features: 1. People need to be able to search for the new feature and learn it. For syntax in particular, that's hard, as you can't search for something unless you know the right terms. Often a library function is better than syntax for precisely this reason. 2. If a new syntax is defined as "equivalent to XXX which is how you write it now", then (a) it immediately violates the "there should be one obvious way to do it" rule, *unless* the new syntax is so compelling as to immediately be seen as the new "obvious" way to do things. And (b) the people having to support older versions of Python (i.e. a *lot* of people) have no incentive to use the new construct because then they'd have to drop support for existing Python versions. Now, none of the above are insurmountable. We do get new syntax features - and they aren't always massive like async or typing. Unpacking generalisations and f-strings are recent new syntax. But you have to have a *really* good story in terms of benefits to pass the bar. And that means a lot more than just "most people on the list weren't actively against it" in the case of a proposal that's already been made and rejected. Regarding your other points, it *is* hard for newcomers to know what's an old idea. We do what we can (even to the extent of sometimes recommending PEPs just so that ideas can be formally rejected for reference) but not everyone reads up on the history, and we try to be forgiving of that. Your original post showed that you had done some research, so thanks for that. Hopefully, we can work on clarifying for people like you why the "it keeps coming up" argument isn't sufficient by itself. As regards "it will take less time in the end to implement it", if only that were true :-) Sadly, most of the people contributing to discussions here (and even though I'm a core dev, I include myself here) don't actually write code for the Python core that often - whether because time to write emails is easier to find than time to code, or for other reasons, isn't that important. So even we were all to spend a week off from Python-ideas, that wouldn't necessarily translate into new patches for Python. I hope that puts the discussion into context. Paul

Hi Paul, Thanks for typing that all out and taking the time to respond to my emails. I think as you say, it might be good to put this somewhere obvious. I did find https://docs.python.org/devguide/langchanges.html and http://www.curiousefficiency.org/posts/2011/02/justifying-python-language-ch... but the things you wrote would be useful to add the former (or be linked from there). It would also be good if there was a counter-point to that blog post of changes (like this one) that are not sufficiently thought through or significant enough to be accepted: it is always good to have examples on both sides. In terms of your "it keeps coming up", maybe there should be a general PEP (or something else) that simply outlines a bunch of ideas (and will be kept adding to) that keep cropping up but have been rejected/received unsympathetically many times? Including maybe links to these threads? Maybe that is something that could save you (and others subscribed) time and effort? H-J On 23 February 2017 at 15:02, Paul Moore <p.f.moore@gmail.com> wrote:

On 23 February 2017 at 15:18, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
Ha. I never even *thought* of putting something like this in the devguide. Thanks for the pointer. I'll try to make some time to polish up my comments and put a PR together for that. I've thought we should have some sort of "list info" page describing things like this and giving some context for posters before now. Possibly linked from the automatic footer the list adds. I don't know who would be able to do something like that, though. Thanks for your suggestions. Paul

On Thu, Feb 23, 2017 at 03:33:32PM +0000, Paul Moore wrote:
Paul, at the moment I have neither the time nor the mental energy to deal with learning the brave New World of Github's way of doing things, but if you want to adapt my "Things That Won't Change" proto-PEP from last month, please feel free to do so! I have an update to the original version, over the next couple of days, time permitting, I'll clean it up and send it to the list.
The obvious places to link to this page are: - the Python-Ideas signup page; - the devguide; - the FAQs. -- Steve

Hi Henk-Jaap, thanks for your "if in for" proposal. Paul's comments are all "motherhood statements" against a generic proposal. It's nothing that would prevent your specific proposal from being accepted or not. And there's no rejected PEP for this feature as far as I can see. Skimming through the other thread about this topic, I remember me not being very offensive against it. I would use it often. IIRC, one result of former discussions were that it would be technically possible. But the other proposer did not convince most thread participants back then. I for one, though, didn't buy the counter-arguments and still don't. They still sound to me like abstract fears. On 23.02.2017 16:18, Henk-Jaap Wagenaar wrote:
Recently, we had a similar discussion about writing an "official" document which might prevent proposal such as yours. I wasn't the only one being offended by this kind of thinking. There are, as you noted, two sides of the table and just because "it keeps coming up" and "was received unsympathetically many times" doesn't mean we shouldn't consider it. Point is, it actually seems sympathetic to many people and this is why it keeps coming up. Nevertheless, a proposal needs consensus. Regards, Sven

On Thu, Feb 23, 2017 at 03:02:18PM +0000, Paul Moore wrote:
We really need a FAQ for this, if there isn't one already.
Indeed. Earlier this year, I started a thread on Things That Won't Change In Python. If I recall correctly, Nick disagreed that it should be a PEP, I started to write up a response to everyone's feedback, and then my PC crashed and I lost the response. I never came back to it. I think its time to do so. I'm fine with the idea of it being a FAQ. https://mail.python.org/pipermail/python-ideas/2017-January/044201.html -- Steve

2017-02-23 5:37 GMT-08:00 Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com>:
I think it might also be difficult to parse. Python currently supports this syntax: In [8]: for x in [1, 2] if True else [1, 2, 3]: ...: print(x) ...: 1 2 I'm not sure the parser could distinguish this structure from the one you propose (which would have a very different meaning) without making it significantly more complicated. Changes that make the parser more complicated than LL(1) have been consistently rejected in the past; see https://www.python.org/dev/peps/pep-3099/.

One does not seem to be able to do this in a generator expression: foo = (x for x in [1, 2] if True else [1, 2, 3]) gives a syntax error, however, adding parenthesis 'solves' this: foo = (x for x in [1, 2] if True else [1, 2, 3]) In the for-loop version, either works. Though I guess this would be even more frowned upon, one can even do: for x in [], print("Here be dragons"): pass Whether it can be implemented in an LL(1) parser, my gut says it could, but this does complicate matters if one were to continue supporting it and create a whirl of confusion. If anything, this shows that there could have been scope for more consistency between the for-statement and generator expression by enforcing parenthesis in the for-loop as well but I think the grammar as it is will be here to stay, unless there is going to be a Python 4 like there is Python 3... I think to be honest this is a pretty big nail in the coffin. H-J On 23 February 2017 at 14:51, Jelle Zijlstra <jelle.zijlstra@gmail.com> wrote:

On Thu, Feb 23, 2017 at 01:37:15PM +0000, Henk-Jaap Wagenaar wrote: [...]
Indeed not. The Pythonic solution is exactly the one you used: DON'T combine the for-loop and if-statement. for x in range(100): if is_prime(x): ... If the use of two lines and two indents is truly a problem, to the point that you really need to refactor to a single line, that's a code smell: your function is probably too big, too complex and does too much, and should be refactored.
- it would mean there is a Pythonic solution to a current 'problem' that does not have one.
It does have a solution: "Don't do it". One common argument is that people can write a for...if in a single expression as part of comprehensions: [... for x in range(100) if is_prime(x)] so they should be able to write the same outside. We can write: [... for x in seqA for y in seqB if y for z in seqC] Does that mean we should be able to write this as a combined statement? for x in seqA for y in seqB if y for z in seqC: ... Certainly not! The fact that comprehensions allow such ugly code is not a feature to be emulated, but something to be discouraged. Comprehensions are limited to being a single expression, and so we have to compromise on good design in order to get the full functionality required. No such compromise is needed with the statement forms of for/if. We can draw the line right at the start, and insist that each statement falls on a line on its own. Deeply nested for...for...for...if...if...if...for... blocks look ugly because they are ugly. Allowing them all on one line makes the Python language worse, not better. It is unfortunate that comprehensions, by their nature, must allow that sort of thing, but that doesn't mean we have to allow it elsewhere. -- Steve

Hey Steven, On 23.02.2017 19:25, Steven D'Aprano wrote:
May I disagree with you here? I write many functions with a single for loop + a single if+continue on a daily basis (usually generators). They don't seem to look like code-smell to me. Not saying they justify this feature but it's easier to read a positive (including) if than a negative one (skipping).
Another disagreement here. Just because it's possible to do ugly stuff with a hammer shouldn't mean we cannot allow hammers. It's an argument neither in favor of nor against the proposal. Sven

On Thu, Feb 23, 2017 at 11:07:49PM +0100, Sven R. Kunze wrote:
I'm sorry, I didn't explain myself well enough. There is nothing wrong with a nested for...if pair of statements. But that does take two lines, and two indents, rather than one: block for ... if ... block versus hypothetical: block for ... if ... block The proposed syntax saves one line, and one indent. That is a saving, but it is not a big saving. If one line and one indent *really* makes a difference to a piece of code, it is probably because you are already deeply nested: class ... def ... def ... try ... try ... while ... try ... if ... with ... if ... while ... for ... if ... # not enough # room here That is already so deeply nested that saving one indent might be important. But the problem isn't the for...if section, it is the ten or a dozen *previous* statements. "I have run out of horizontal space" is the code-smell, not "I have a for loop and an if branch". Most of the time, "save one line of code" or "save one indent" is not a big win. It it insignificant: most of the time, extra lines are cheap, and there is plenty of room for all the indent levels needed. There is one obvious exception to the rule: if ... else: if ... else: if ... else: if ... That can get pretty costly in terms of indent levels very quickly. And that is why Python has elif: if ... elif ... elif ... elif ... So don't misunderstand me. I do appreciate that sometimes saving indents and lines is important. But what I am saying is that in *this* case, it is rarely important enough to matter, and when it does matter, your code probably has bigger problems than just the for...if blocks.
Since code is read more often than it is written, good programming languages are pretty programming languages. That's why most of us choose Python: its not the most efficient language, or fastest running language, or most powerful language, but it is fast enough, efficient enough, powerful enough, and most importantly, it is pretty. By which I mean it is relatively easy to read (at least for English-readers), which makes it easy to write, debug and maintain. If we want to keep Python pretty, we should discourage things which are ugly. Discourage, or even outright ban them. Some features are on the borderline. There is a grey area where it comes to the subjective aesthetic judgement of the language Dictator. I think that this is one of those areas, and I hope that we are correctly channelling the BDFL. Because for...if...for...if... is on the boundary, we can allow it in one case (comprehensions) and forbid it in another (statements): - in a series of nested statements, the benefit of allowing the for...if all on one line is not enough to make up for the risk of people misusing it; - in a comprehension, the benefit is greater, which is enough to make up for the risk of people misusing it. Because a comprehension is an expression, adding an extra line and an extra indent is not usually helpful. It may mess up the expression it is embedded in and lead to messy code: result = some_function(arg, [comprehension that goes over multiple lines and indents], spam, eggs, cheese) + 1 print(result) That's probably not helpful, and possibly even confusing. So for comprehensions, we can relax the rule about one indent level per for or if statement. The reason we have different syntax for comprehensions and statements is that they are different kinds of code, used in different ways. -- Steve

On Fri, Feb 24, 2017 at 3:28 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Don't forget that you can rewrite a "for-if" using two additional lines and no indents, rather than one line and one indent: for ...: if not (...): continue ... ... So you can take your pick which version you want. Granted, I can still see value in the for-if statement, but not enough to justify new syntax. ChrisA

On 23 February 2017 at 13:37, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
Thanks for your interest, but as you note this has already been proposed and rejected (from my personal recollection, more than once). So the key question is surely, what are you proposing that wasn't already discussed in previous threads, and why do you think that the new aspect of your proposal is likely to change Guido's mind? Sorry to be blunt, but rehashing an already extensively discussed idea isn't that productive for anyone. Paul

Just as a reference, I think the most recent reincarnation of this thread was: https://mail.python.org/pipermail/python-ideas/2016-September/042270.html On 23 February 2017 at 13:46, Paul Moore <p.f.moore@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager www.machinalis.com Skype: @dmoisset

Hi Paul, Daniel, others, That is fair enough and the right amount of blunt. Let me go through the points that were made in that thread (I have not found any other threads, if someone links to them, I will go through them as well): ----- From: https://mail.python.org/pipermail/python-dev/2007-November/075258.html, alternative solution (in current language):
for x in (x for x in range if is_prime(x)): # do something with x
This statement seems overly complicated for what it is trying to achieve and is semantically much harder to parse than the proposed alternative, e.g. there is repetition of the string "for x in". ---- A similar point to where I started from in https://mail.python.org/piperm ail/python-ideas/2016-September/042600.html:
---- The thread Daniel mentioned was ended by the following post https://mail.python.org/pipermail/python-ideas/2016-September/042285.html
I am not sure I agree with what he is saying (or I am not following it...). I think no-one in that thread particularly demonstrated why this could not supersede all equivalent solutions, even if the if is longer (but not complex), one can simply do: for x in range(10) \ if is_prime(x) and is_overabundant(x) and is_perfect(x) and x != 5: # do something with x where you would line up the if with the range/... on the previous line (this example is silly, because the conditions cannot be satisfied). This in my view would still be clearer and more concise than the alternative solutions. The emails in the threads seem to indicate that almost everyone is a shade of grey here, where some really like it (but can life without), some think it is alright but don't particularly mind, and some think it is not the worth the cost or would allow abuse. No-one seems to fundamentally hate the idea, or in a alternative world where it was already in Python, would suggest taking it out (even if it a backwards-incompatible epoch like 2->3 was approaching) though my reading between the lines of emails can be wrong. I think Erik's email (see above) shows this most clearly. In a straw poll at the company I work at everyone was in favour, though they obviously are not in charge of implementing or changing documentation so that is easy for them to say, they've got no skin in the game. I don't know whether it is common for such an idea to be brought up again and again by newcomers/those who don't strolls the archives enough, but if it keeps being brought up, and the main argument against is it would take time and effort to document and implement for little benefit, if Python sticks around for a long enough time, it will end up taking less time simply implement it! Best, Henk-Jaap On 23 February 2017 at 13:54, Daniel Moisset <dmoisset@machinalis.com> wrote:
On 23 February 2017 at 13:54, Daniel Moisset <dmoisset@machinalis.com> wrote:

On 23 February 2017 at 14:20, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
We really need a FAQ for this, if there isn't one already. You quoted Nick referring to a post I'd already made on this, and while I'm afraid I don't have time to find a link for you, I'll try to summarise again here. The bar for syntax changes to Python (and also library changes, although to a slightly lesser extent) is deliberately very high. This is not because people don't like proposals, but rather because the proposers consistently and drastically underestimate the cost of adding new features to the language. Things that need to be factored into the cost of a change: 1. Written materials, such as books, training courses, blog posts will be out of date, at best offering obsolete advice, at worst being outright wrong. Either the authors have extra work to do to change them, or the readers need to learn the "new truth", probably by making mistakes that they could have avoided if the material were correct. 2. Core developers need to understand the implementation of the new feature in order to support it. 3. Unintended consequences and/or problems with the design of the new feature (= bugs) need to be fixed. 4. People writing code that needs to support multiple versions of Python probably won't benefit, as they'll have to avoid the feature. But they will pay costs: a) They need to review that decision over time - is the new feature compelling enough that we should drop support for older versions yet? b) If there's an existing way of writing the construct, why ever change to the new version at all? c) PRs written by people used to the new feature will need reviewing and fixing for compatibility. 5. People not interested in the new feature will encounter it in other people's code and will need to understand it. 6. Someone has to code it. It's often not at all clear whether the proposer is offering to spend the time implementing the feature, and we typically don't bluntly say "well, will you write the code?" both because it's a bit aggressive, and also because an answer of "yes" isn't enough by itself - so we don't want to mislead people that the *only* problem is finding someone to code the change. There's probably others that I have missed. In addition, there's a couple of other points, not directly related to cost but still downsides of new features: 1. People need to be able to search for the new feature and learn it. For syntax in particular, that's hard, as you can't search for something unless you know the right terms. Often a library function is better than syntax for precisely this reason. 2. If a new syntax is defined as "equivalent to XXX which is how you write it now", then (a) it immediately violates the "there should be one obvious way to do it" rule, *unless* the new syntax is so compelling as to immediately be seen as the new "obvious" way to do things. And (b) the people having to support older versions of Python (i.e. a *lot* of people) have no incentive to use the new construct because then they'd have to drop support for existing Python versions. Now, none of the above are insurmountable. We do get new syntax features - and they aren't always massive like async or typing. Unpacking generalisations and f-strings are recent new syntax. But you have to have a *really* good story in terms of benefits to pass the bar. And that means a lot more than just "most people on the list weren't actively against it" in the case of a proposal that's already been made and rejected. Regarding your other points, it *is* hard for newcomers to know what's an old idea. We do what we can (even to the extent of sometimes recommending PEPs just so that ideas can be formally rejected for reference) but not everyone reads up on the history, and we try to be forgiving of that. Your original post showed that you had done some research, so thanks for that. Hopefully, we can work on clarifying for people like you why the "it keeps coming up" argument isn't sufficient by itself. As regards "it will take less time in the end to implement it", if only that were true :-) Sadly, most of the people contributing to discussions here (and even though I'm a core dev, I include myself here) don't actually write code for the Python core that often - whether because time to write emails is easier to find than time to code, or for other reasons, isn't that important. So even we were all to spend a week off from Python-ideas, that wouldn't necessarily translate into new patches for Python. I hope that puts the discussion into context. Paul

Hi Paul, Thanks for typing that all out and taking the time to respond to my emails. I think as you say, it might be good to put this somewhere obvious. I did find https://docs.python.org/devguide/langchanges.html and http://www.curiousefficiency.org/posts/2011/02/justifying-python-language-ch... but the things you wrote would be useful to add the former (or be linked from there). It would also be good if there was a counter-point to that blog post of changes (like this one) that are not sufficiently thought through or significant enough to be accepted: it is always good to have examples on both sides. In terms of your "it keeps coming up", maybe there should be a general PEP (or something else) that simply outlines a bunch of ideas (and will be kept adding to) that keep cropping up but have been rejected/received unsympathetically many times? Including maybe links to these threads? Maybe that is something that could save you (and others subscribed) time and effort? H-J On 23 February 2017 at 15:02, Paul Moore <p.f.moore@gmail.com> wrote:

On 23 February 2017 at 15:18, Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com> wrote:
Ha. I never even *thought* of putting something like this in the devguide. Thanks for the pointer. I'll try to make some time to polish up my comments and put a PR together for that. I've thought we should have some sort of "list info" page describing things like this and giving some context for posters before now. Possibly linked from the automatic footer the list adds. I don't know who would be able to do something like that, though. Thanks for your suggestions. Paul

On Thu, Feb 23, 2017 at 03:33:32PM +0000, Paul Moore wrote:
Paul, at the moment I have neither the time nor the mental energy to deal with learning the brave New World of Github's way of doing things, but if you want to adapt my "Things That Won't Change" proto-PEP from last month, please feel free to do so! I have an update to the original version, over the next couple of days, time permitting, I'll clean it up and send it to the list.
The obvious places to link to this page are: - the Python-Ideas signup page; - the devguide; - the FAQs. -- Steve

Hi Henk-Jaap, thanks for your "if in for" proposal. Paul's comments are all "motherhood statements" against a generic proposal. It's nothing that would prevent your specific proposal from being accepted or not. And there's no rejected PEP for this feature as far as I can see. Skimming through the other thread about this topic, I remember me not being very offensive against it. I would use it often. IIRC, one result of former discussions were that it would be technically possible. But the other proposer did not convince most thread participants back then. I for one, though, didn't buy the counter-arguments and still don't. They still sound to me like abstract fears. On 23.02.2017 16:18, Henk-Jaap Wagenaar wrote:
Recently, we had a similar discussion about writing an "official" document which might prevent proposal such as yours. I wasn't the only one being offended by this kind of thinking. There are, as you noted, two sides of the table and just because "it keeps coming up" and "was received unsympathetically many times" doesn't mean we shouldn't consider it. Point is, it actually seems sympathetic to many people and this is why it keeps coming up. Nevertheless, a proposal needs consensus. Regards, Sven

On Thu, Feb 23, 2017 at 03:02:18PM +0000, Paul Moore wrote:
We really need a FAQ for this, if there isn't one already.
Indeed. Earlier this year, I started a thread on Things That Won't Change In Python. If I recall correctly, Nick disagreed that it should be a PEP, I started to write up a response to everyone's feedback, and then my PC crashed and I lost the response. I never came back to it. I think its time to do so. I'm fine with the idea of it being a FAQ. https://mail.python.org/pipermail/python-ideas/2017-January/044201.html -- Steve

2017-02-23 5:37 GMT-08:00 Henk-Jaap Wagenaar <wagenaarhenkjaap@gmail.com>:
I think it might also be difficult to parse. Python currently supports this syntax: In [8]: for x in [1, 2] if True else [1, 2, 3]: ...: print(x) ...: 1 2 I'm not sure the parser could distinguish this structure from the one you propose (which would have a very different meaning) without making it significantly more complicated. Changes that make the parser more complicated than LL(1) have been consistently rejected in the past; see https://www.python.org/dev/peps/pep-3099/.

One does not seem to be able to do this in a generator expression: foo = (x for x in [1, 2] if True else [1, 2, 3]) gives a syntax error, however, adding parenthesis 'solves' this: foo = (x for x in [1, 2] if True else [1, 2, 3]) In the for-loop version, either works. Though I guess this would be even more frowned upon, one can even do: for x in [], print("Here be dragons"): pass Whether it can be implemented in an LL(1) parser, my gut says it could, but this does complicate matters if one were to continue supporting it and create a whirl of confusion. If anything, this shows that there could have been scope for more consistency between the for-statement and generator expression by enforcing parenthesis in the for-loop as well but I think the grammar as it is will be here to stay, unless there is going to be a Python 4 like there is Python 3... I think to be honest this is a pretty big nail in the coffin. H-J On 23 February 2017 at 14:51, Jelle Zijlstra <jelle.zijlstra@gmail.com> wrote:

On Thu, Feb 23, 2017 at 01:37:15PM +0000, Henk-Jaap Wagenaar wrote: [...]
Indeed not. The Pythonic solution is exactly the one you used: DON'T combine the for-loop and if-statement. for x in range(100): if is_prime(x): ... If the use of two lines and two indents is truly a problem, to the point that you really need to refactor to a single line, that's a code smell: your function is probably too big, too complex and does too much, and should be refactored.
- it would mean there is a Pythonic solution to a current 'problem' that does not have one.
It does have a solution: "Don't do it". One common argument is that people can write a for...if in a single expression as part of comprehensions: [... for x in range(100) if is_prime(x)] so they should be able to write the same outside. We can write: [... for x in seqA for y in seqB if y for z in seqC] Does that mean we should be able to write this as a combined statement? for x in seqA for y in seqB if y for z in seqC: ... Certainly not! The fact that comprehensions allow such ugly code is not a feature to be emulated, but something to be discouraged. Comprehensions are limited to being a single expression, and so we have to compromise on good design in order to get the full functionality required. No such compromise is needed with the statement forms of for/if. We can draw the line right at the start, and insist that each statement falls on a line on its own. Deeply nested for...for...for...if...if...if...for... blocks look ugly because they are ugly. Allowing them all on one line makes the Python language worse, not better. It is unfortunate that comprehensions, by their nature, must allow that sort of thing, but that doesn't mean we have to allow it elsewhere. -- Steve

Hey Steven, On 23.02.2017 19:25, Steven D'Aprano wrote:
May I disagree with you here? I write many functions with a single for loop + a single if+continue on a daily basis (usually generators). They don't seem to look like code-smell to me. Not saying they justify this feature but it's easier to read a positive (including) if than a negative one (skipping).
Another disagreement here. Just because it's possible to do ugly stuff with a hammer shouldn't mean we cannot allow hammers. It's an argument neither in favor of nor against the proposal. Sven

On Thu, Feb 23, 2017 at 11:07:49PM +0100, Sven R. Kunze wrote:
I'm sorry, I didn't explain myself well enough. There is nothing wrong with a nested for...if pair of statements. But that does take two lines, and two indents, rather than one: block for ... if ... block versus hypothetical: block for ... if ... block The proposed syntax saves one line, and one indent. That is a saving, but it is not a big saving. If one line and one indent *really* makes a difference to a piece of code, it is probably because you are already deeply nested: class ... def ... def ... try ... try ... while ... try ... if ... with ... if ... while ... for ... if ... # not enough # room here That is already so deeply nested that saving one indent might be important. But the problem isn't the for...if section, it is the ten or a dozen *previous* statements. "I have run out of horizontal space" is the code-smell, not "I have a for loop and an if branch". Most of the time, "save one line of code" or "save one indent" is not a big win. It it insignificant: most of the time, extra lines are cheap, and there is plenty of room for all the indent levels needed. There is one obvious exception to the rule: if ... else: if ... else: if ... else: if ... That can get pretty costly in terms of indent levels very quickly. And that is why Python has elif: if ... elif ... elif ... elif ... So don't misunderstand me. I do appreciate that sometimes saving indents and lines is important. But what I am saying is that in *this* case, it is rarely important enough to matter, and when it does matter, your code probably has bigger problems than just the for...if blocks.
Since code is read more often than it is written, good programming languages are pretty programming languages. That's why most of us choose Python: its not the most efficient language, or fastest running language, or most powerful language, but it is fast enough, efficient enough, powerful enough, and most importantly, it is pretty. By which I mean it is relatively easy to read (at least for English-readers), which makes it easy to write, debug and maintain. If we want to keep Python pretty, we should discourage things which are ugly. Discourage, or even outright ban them. Some features are on the borderline. There is a grey area where it comes to the subjective aesthetic judgement of the language Dictator. I think that this is one of those areas, and I hope that we are correctly channelling the BDFL. Because for...if...for...if... is on the boundary, we can allow it in one case (comprehensions) and forbid it in another (statements): - in a series of nested statements, the benefit of allowing the for...if all on one line is not enough to make up for the risk of people misusing it; - in a comprehension, the benefit is greater, which is enough to make up for the risk of people misusing it. Because a comprehension is an expression, adding an extra line and an extra indent is not usually helpful. It may mess up the expression it is embedded in and lead to messy code: result = some_function(arg, [comprehension that goes over multiple lines and indents], spam, eggs, cheese) + 1 print(result) That's probably not helpful, and possibly even confusing. So for comprehensions, we can relax the rule about one indent level per for or if statement. The reason we have different syntax for comprehensions and statements is that they are different kinds of code, used in different ways. -- Steve

On Fri, Feb 24, 2017 at 3:28 PM, Steven D'Aprano <steve@pearwood.info> wrote:
Don't forget that you can rewrite a "for-if" using two additional lines and no indents, rather than one line and one indent: for ...: if not (...): continue ... ... So you can take your pick which version you want. Granted, I can still see value in the for-if statement, but not enough to justify new syntax. ChrisA
participants (7)
-
Chris Angelico
-
Daniel Moisset
-
Henk-Jaap Wagenaar
-
Jelle Zijlstra
-
Paul Moore
-
Steven D'Aprano
-
Sven R. Kunze