1def gen(): 2 yield 1 3 yield 2 4 yield 3 5 yield 4 6 7def gen2(): 8 yield -1 9 print((yield from gen())) 10 yield 10 11 yield 11 12 13g = gen2() 14print(next(g)) 15print(next(g)) 16g.close() 17try: 18 print(next(g)) 19except StopIteration: 20 print("StopIteration") 21 22 23# Now variation of same test, but with leaf generator 24# swallowing GeneratorExit exception - its upstream gen 25# generator should still receive one. 26def gen3(): 27 yield 1 28 try: 29 yield 2 30 except GeneratorExit: 31 print("leaf caught GeneratorExit and swallowed it") 32 return 33 yield 3 34 yield 4 35 36def gen4(): 37 yield -1 38 try: 39 print((yield from gen3())) 40 except GeneratorExit: 41 print("delegating caught GeneratorExit") 42 raise 43 yield 10 44 yield 11 45 46g = gen4() 47print(next(g)) 48print(next(g)) 49print(next(g)) 50g.close() 51try: 52 print(next(g)) 53except StopIteration: 54 print("StopIteration") 55 56 57# Yet another variation - leaf generator gets GeneratorExit, 58# and reraises a new GeneratorExit. This still should close chain properly. 59def gen5(): 60 yield 1 61 try: 62 yield 2 63 except GeneratorExit: 64 print("leaf caught GeneratorExit and reraised GeneratorExit") 65 raise GeneratorExit(123) 66 yield 3 67 yield 4 68 69def gen6(): 70 yield -1 71 try: 72 print((yield from gen5())) 73 except GeneratorExit: 74 print("delegating caught GeneratorExit") 75 raise 76 yield 10 77 yield 11 78 79g = gen6() 80print(next(g)) 81print(next(g)) 82print(next(g)) 83g.close() 84try: 85 print(next(g)) 86except StopIteration: 87 print("StopIteration") 88 89# case where generator ignores the close request and yields instead 90def gen7(): 91 try: 92 yield 123 93 except GeneratorExit: 94 yield 456 95 96g = gen7() 97print(next(g)) 98try: 99 g.close() 100except RuntimeError: 101 print('RuntimeError') 102 103# case where close is propagated up to a built-in iterator 104def gen8(): 105 g = range(2) 106 yield from g 107g = gen8() 108print(next(g)) 109g.close() 110 111# case with a user-defined close method 112class Iter: 113 def __iter__(self): 114 return self 115 def __next__(self): 116 return 1 117 def close(self): 118 print('close') 119def gen9(): 120 yield from Iter() 121g = gen9() 122print(next(g)) 123g.close() 124