Does Python execute code only if iteration (with a generator) did not start for the loop?

The else block in the for / else clause is triggered if the iteration ends but break is not interrupted, so I read .

Is there a language construct that would allow me to write something that only runs if the for loop did not start with an iteration? If I used tuple or list , I would do something like this:

 if seq: for x in seq: # something else: # something else 

But when I use the generator, I do not get the behavior that I want:

 >>> g = (x for x in range(2)) >>> for x in g: ... print x ... else: ... print "done" ... 0 1 done # I don't want "done" here >>> g = (x for x in range(2) if x > 1) >>> if g: ... for x in g: ... print x ... else: ... print "done" ... >>> # I was expecting "done" here 

How can I do this without exhausting the creation of a tuple or list from the generator, as well as using the for loop? I could use next() in a while and try to catch StopIteration , but I would like to see if there is a good way to do this with for .

+4
source share
7 answers

I can't think of a better way than updating a boolean inside a for loop.

 any_results = False for x in g: any_results = True print x if not any_results: print 'Done' 
+3
source
 n = -1 for n, i in enumerate(it): do_stuff() if n < 0: print 'Done' 
+3
source

You can use the generator function:

next takes an optional second argument, which can be used to specify a default value if the iterator is exhausted.

 def func(lis): g = (x for x in lis if x > 1) flag = object() # expected to be unique nex = next(g, flag) # will return flag if genexp is empty if nex is not flag: yield nex for item in g: yield item else: yield "done" for x in func(range(2)): print x print "------" for x in func(range(4)): print x 

Output:

 done ------ 2 3 
+2
source

I found this solution much better. Check this link for more information ( http://python-notes.curiousefficiency.org/en/latest/python_concepts/break_else.html ).

You can use a special watch: x = no_data = object ()

 x = no_data = object() for x in data: ....... if x is no_data: print "Loop did not run" 

object () returns a faceless object that is the base for all classes.

checks if both objects are the same (x - no_data). If they remain the same, it means that the control never fell into the for loop.

+1
source

I think a good way to find out if a loop is actually running using a loop variable

 lv= 1 for x in g: lv = lv+1 print x if (lv == 1): print 'Done' 

My syntax may be wrong because I'm not a python guy ..

0
source

You can write a wrapper that counts the number of iterations. This has the advantage that it works with more exotic listings. In python3, it will be something like:

 import sys from glob import iglob class GenCount(object): def __init__(self, gen): self._iter = iter(gen) self.count = 0 def __next__(self): val = self._iter.__next__() self.count += 1 return val def __iter__(self): return self c = GenCount(iglob(sys.argv[1])) for fn in c: print(fn) print(c.count) c = GenCount(iglob(sys.argv[1])) print([fn for fn in c]) print(c.count) 
0
source

In the example here, do you need an additional design?

 caught = None for item in x: caught = item print caught if caught != None: print "done" 

* Edited for OP commen * t

-one
source

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


All Articles