"in" syntax in loops

This is somewhat related to my previous post that got a nice reply from Dan, and it was nice to hear that it’s not just noob eyes that sometimes think that “pythony” syntax actually is more difficult to read than “basicy” (even though Python is lauded as an easy to read language, I often find it very obfuscated somehow).

I just completed a kata on codewars with the text to alphabet position, which went fine, the best practice solution was

return ' '.join(str(ord(c) - 96) for c in text.lower() if c.isalpha())

I’d forgotten about the “isalpha” method, but I’d tried a similar loop construct but it didn’t work:

for x in text.lower() if ord(x) in range(97,123)

so I went back to this style (which as before seems to be a bit easier to follow whats going on)

result = []
    for x in text.lower():
        if ord(x) in range(97, 123):
            result.append(f"{str(ord(x)-96)} ")
    return " ".join(result)

my question is really, what part of the syntax should I look up to fully understand where mine went wrong, is it the “in” part or is it the stuff that the “for” keyword is getting.

I see that in the best practice solution the extra bit in the for loop is a simple “if bool” whereas mine is a bit more long winded as “if… in…” bool, is that the problem that this is a full expression?

and actually why do neither of these work as a loop construct

for x in text.lower() if x.isalpha():
for x in text.lower() if x.isalpha()

when this works just fine in the optimal solution

return ' '.join(str(ord(c) - 96) for c in text.lower() if c.isalpha()

hmm, but then this worked fine in a subsequent kata

return sum(1 for x in arr if x in happy)

maybe in my very first question, if I’d done

span =  [97,98,...etc..., 122]
for x in text.lower() if ord(x) in span

i.e. is it the range function iterating that caused the problem, I will check this
however, I am still not sure why the other example works as a single line loop in a return but you cannot use the same loop on its own as normal

no its definitely related to it being sent back via the return statement, so basically, what is the reference material I should read to understand how for loop constructions with conditionals can work as something in a return but not on its own

I’ve edited your post for readability. When you enter a code block into a forum post, please precede it with a separate line of three backticks and follow it with a separate line of three backticks to make it easier to read.

You can also use the “preformatted text” tool in the editor (</>) to add backticks around text.

See this post to find the backtick on your keyboard.
Note: Backticks (`) are not single quotes (’).

awww crap, sorry! I thought I had clicked that, my bad, I’ll try to use the preview feature in future :slight_smile: thanks for the help

OK I got an answer from stackoverflow so posting here for posterity

The for keyword is used for two related but not equal things:

  • A for statement is a classical loop working on a block of statements for each iteration step.
for <target> in <iterable>:
      <block>

Notably, the for statement can run arbitrary blocks, including but not limited to if statements.

  • A for display expression is part of a fixed expression ( list , set , dict comprehension or generator expression) to map and filter iterables.
[<map> for <target> in <iterable> if <filter>]

Notably, the forinif are a fixed expression syntax with well-defined meaning only when used together .

The for statement does not have to be special-cased with an if , since it can include a regular if statement. The for display must be special-cased with an if , since the latter is defined in terms of the former.

the short answer is I have not really got to the point of reading up properly on the separately defined for-in-if constructs as generators (but see them all over the place even in beginner python tutorials), and you can’t just lift them out and use them as a for loop instead