Join conditions in a for loop

Python allows the " if " condition in list comprehension, for example:

 [l for l in lines if l.startswith('example')] 

This function is absent in the regular " for " loop, so if not:

 for line in lines if line.startswith('example'): statements 

you need to evaluate the condition in the loop:

 for line in lines: if line.startswith('example'): statements 

or insert a generator expression, for example:

 for line in [l for l in lines if l.startswith('example')]: statements 

Do I understand correctly? Is there a better or more pythonic way than the ones listed above to achieve the same result of adding a condition to the for loop?

Please note that “strings” is chosen as an example; any collection or generator can be there.

+5
source share
4 answers

Some nice ideas came from other answers and comments, but I think this recent discussion of Python ideas and its continuation is the best answer to this question.

To summarize: the idea has already been discussed in the past, and the benefits were not sufficient to motivate syntax changes, given:

  • Increased language complexity and impact on learning curve

  • technical changes in all implementations: CPython, Jython, Pypy ..

  • Possible strange situations: extreme use of syntax can lead to

One point that people seem to be very considering is to avoid casting Perl-like complexity that compromises maintainability.

This is the message and this possible alternative (almost already appearing on this page) to the composite if-statement in the for-loop:

 # nested if for l in lines: if l.startswith('example'): body # continue, to put an accent on exceptional case for l in lines: if not l.startswith('example'): continue body # hacky way of generator expression # (better than comprehension as does not store a list) for l in (l for l in lines if l.startswith('example')): body() # and its named version def gen(lines): return (l for l in lines if l.startswith('example')) for line in gen(lines): body # functional style for line in filter(lambda l: l.startswith('example'), lines): body() 
+2
source

Maybe not Pythonic, but you could filter lines.

 for line in filter(lambda l: l.startswith('example'), lines): print(line) 

And you can define your own filter function, of course, if this lambda bothers you or you need more complex filtering.

 def my_filter(line): return line.startswith('example') or line.startswith('sample') for line in filter(my_filter, lines): print(line) 

I would say that the condition inside the loop is better, because you do not support the “filtered” list in memory when repeating along lines.

So that would be easy

 for line in file: if not my_filter(line): continue # statements 
+1
source

Not that the function is missing, I cannot think of how this could be done, except in some special cases. (l for l in lines if l.startswith('example')) is a generator object, and the variable l is local to this object. for sees only what was returned by the __next__ generator.

for very different because the result of the generator must be bound to a variable in the call area. You could write

 for line in (line for line in lines if l.startswith('example')): foo(line) 

safe because the two line are in different areas.

In addition, the generator does not need to return only its local variable. He can evaluate any expression. How would you cut it?

 for line in (foo(line)+'bar' for line in lines if line.startswith('example')): statements 

Suppose you have a list of lists

 for l in (l[:] for l in list_of_lists if l): l.append('modified') 

This should not be added to the source lists.

0
source

Is there a better or more pythonic way than the ones listed above to achieve the same result of adding a condition to the for loop?

No, no, and should not be; this served as the basis for why lists first fall. From the corresponding PEP :

List matching provides a more concise way to create lists in situations where map() and filter() and / or nested loops are currently used.

Explanation of lists is an alternative for nested for , if s; why do you want an alternative to an alternative?

If you need to use if with for , you insert it inside it, if you do not want to do this, you use list comprehension. Flat is better than nested , but readability indicators; allowing if lead to long ugly lines that are harder to visually disassemble.

0
source

Source: https://habr.com/ru/post/1259736/


All Articles