290_iter.py 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. a = [1, 2, 3]
  2. a = iter(a)
  3. total = 0
  4. while True:
  5. try:
  6. obj = next(a)
  7. except StopIteration:
  8. break
  9. total += obj
  10. assert total == 6
  11. class Task:
  12. def __init__(self, n):
  13. self.n = n
  14. def __iter__(self):
  15. self.i = 0
  16. return self
  17. def __next__(self):
  18. if self.i == self.n:
  19. raise StopIteration
  20. self.i += 1
  21. return self.i
  22. a = Task(3)
  23. assert sum(a) == 6
  24. i = iter(Task(5))
  25. assert next(i) == 1
  26. assert next(i) == 2
  27. assert next(i) == 3
  28. assert next(i) == 4
  29. assert next(i) == 5
  30. try:
  31. next(i)
  32. exit(1)
  33. except StopIteration:
  34. pass
  35. a = iter([1])
  36. assert next(a) == 1
  37. try:
  38. next(a)
  39. exit(1)
  40. except StopIteration:
  41. pass
  42. # --- StopIteration carries the right value ------------------------------
  43. # `py_next` reports exhaustion without building a StopIteration object, so the
  44. # object has to be reconstructed faithfully wherever one is actually observable.
  45. it = iter([1])
  46. assert next(it) == 1
  47. try:
  48. next(it)
  49. exit(1)
  50. except StopIteration as e:
  51. assert e.args == ()
  52. assert e.value is None
  53. assert repr(e) == 'StopIteration()'
  54. assert next(iter([]), 'dflt') == 'dflt'
  55. def gen_with_return():
  56. yield 1
  57. return 42
  58. it = iter(gen_with_return())
  59. assert next(it) == 1
  60. try:
  61. next(it)
  62. exit(1)
  63. except StopIteration as e:
  64. assert e.args == (42,)
  65. assert e.value == 42
  66. def gen_bare_return():
  67. yield 1
  68. it = iter(gen_bare_return())
  69. assert next(it) == 1
  70. try:
  71. next(it)
  72. exit(1)
  73. except StopIteration as e:
  74. assert e.value is None
  75. # `yield from` reads the value out of the exhausted sub-iterator
  76. def outer_with_return():
  77. got = yield from gen_with_return()
  78. yield got
  79. assert list(outer_with_return()) == [1, 42]
  80. def outer_bare_return():
  81. got = yield from gen_bare_return()
  82. yield got
  83. assert list(outer_bare_return()) == [1, None]
  84. class RaisesWithValue:
  85. def __iter__(self):
  86. return self
  87. def __next__(self):
  88. raise StopIteration('V')
  89. def outer_user_iter():
  90. got = yield from RaisesWithValue()
  91. yield got
  92. assert list(outer_user_iter()) == ['V']
  93. # --- every builtin iterator still terminates ---------------------------
  94. assert list(iter([1, 2])) == [1, 2]
  95. assert list(iter((1, 2))) == [1, 2]
  96. assert list(range(3)) == [0, 1, 2]
  97. assert list('ab') == ['a', 'b']
  98. assert ''.join(iter(['a', 'b'])) == 'ab'
  99. d = {'x': 1, 'y': 2}
  100. assert sorted(d.keys()) == ['x', 'y']
  101. assert sorted(d.values()) == [1, 2]
  102. assert sorted(d.items()) == [('x', 1), ('y', 2)]
  103. # a dict mutated mid-iteration must still be reported as an error
  104. try:
  105. for k in d:
  106. d['z'] = 3
  107. exit(1)
  108. except RuntimeError:
  109. pass