test_genexps.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. doctests = """
  2. Test simple loop with conditional
  3. >>> sum(i*i for i in range(100) if i&1 == 1)
  4. 166650
  5. Test simple nesting
  6. >>> list((i,j) for i in range(3) for j in range(4) )
  7. [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
  8. Test nesting with the inner expression dependent on the outer
  9. >>> list((i,j) for i in range(4) for j in range(i) )
  10. [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)]
  11. Make sure the induction variable is not exposed
  12. >>> i = 20
  13. >>> sum(i*i for i in range(100))
  14. 328350
  15. >>> i
  16. 20
  17. Test first class
  18. >>> g = (i*i for i in range(4))
  19. >>> type(g)
  20. <type 'generator'>
  21. >>> list(g)
  22. [0, 1, 4, 9]
  23. Test direct calls to next()
  24. >>> g = (i*i for i in range(3))
  25. >>> g.next()
  26. 0
  27. >>> g.next()
  28. 1
  29. >>> g.next()
  30. 4
  31. >>> g.next()
  32. Traceback (most recent call last):
  33. File "<pyshell#21>", line 1, in -toplevel-
  34. g.next()
  35. StopIteration
  36. Does it stay stopped?
  37. >>> g.next()
  38. Traceback (most recent call last):
  39. File "<pyshell#21>", line 1, in -toplevel-
  40. g.next()
  41. StopIteration
  42. >>> list(g)
  43. []
  44. Test running gen when defining function is out of scope
  45. >>> def f(n):
  46. ... return (i*i for i in xrange(n))
  47. >>> list(f(10))
  48. [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  49. >>> def f(n):
  50. ... return ((i,j) for i in xrange(3) for j in xrange(n))
  51. >>> list(f(4))
  52. [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
  53. >>> def f(n):
  54. ... return ((i,j) for i in xrange(3) for j in xrange(4) if j in xrange(n))
  55. >>> list(f(4))
  56. [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
  57. >>> list(f(2))
  58. [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)]
  59. Verify that parenthesis are required in a statement
  60. >>> def f(n):
  61. ... return i*i for i in xrange(n)
  62. Traceback (most recent call last):
  63. ...
  64. SyntaxError: invalid syntax
  65. Verify that parenthesis are required when used as a keyword argument value
  66. >>> dict(a = i for i in xrange(10))
  67. Traceback (most recent call last):
  68. ...
  69. SyntaxError: invalid syntax
  70. Verify that parenthesis are required when used as a keyword argument value
  71. >>> dict(a = (i for i in xrange(10))) #doctest: +ELLIPSIS
  72. {'a': <generator object <genexpr> at ...>}
  73. Verify early binding for the outermost for-expression
  74. >>> x=10
  75. >>> g = (i*i for i in range(x))
  76. >>> x = 5
  77. >>> list(g)
  78. [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
  79. Verify that the outermost for-expression makes an immediate check
  80. for iterability
  81. >>> (i for i in 6)
  82. Traceback (most recent call last):
  83. File "<pyshell#4>", line 1, in -toplevel-
  84. (i for i in 6)
  85. TypeError: 'int' object is not iterable
  86. Verify late binding for the outermost if-expression
  87. >>> include = (2,4,6,8)
  88. >>> g = (i*i for i in range(10) if i in include)
  89. >>> include = (1,3,5,7,9)
  90. >>> list(g)
  91. [1, 9, 25, 49, 81]
  92. Verify late binding for the innermost for-expression
  93. >>> g = ((i,j) for i in range(3) for j in range(x))
  94. >>> x = 4
  95. >>> list(g)
  96. [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)]
  97. Verify re-use of tuples (a side benefit of using genexps over listcomps)
  98. >>> tupleids = map(id, ((i,i) for i in xrange(10)))
  99. >>> int(max(tupleids) - min(tupleids))
  100. 0
  101. Verify that syntax error's are raised for genexps used as lvalues
  102. >>> (y for y in (1,2)) = 10
  103. Traceback (most recent call last):
  104. ...
  105. File "<doctest test.test_genexps.__test__.doctests[40]>", line 1
  106. SyntaxError: can't assign to generator expression
  107. >>> (y for y in (1,2)) += 10
  108. Traceback (most recent call last):
  109. ...
  110. File "<doctest test.test_genexps.__test__.doctests[41]>", line 1
  111. SyntaxError: can't assign to generator expression
  112. ########### Tests borrowed from or inspired by test_generators.py ############
  113. Make a generator that acts like range()
  114. >>> yrange = lambda n: (i for i in xrange(n))
  115. >>> list(yrange(10))
  116. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
  117. Generators always return to the most recent caller:
  118. >>> def creator():
  119. ... r = yrange(5)
  120. ... print "creator", r.next()
  121. ... return r
  122. >>> def caller():
  123. ... r = creator()
  124. ... for i in r:
  125. ... print "caller", i
  126. >>> caller()
  127. creator 0
  128. caller 1
  129. caller 2
  130. caller 3
  131. caller 4
  132. Generators can call other generators:
  133. >>> def zrange(n):
  134. ... for i in yrange(n):
  135. ... yield i
  136. >>> list(zrange(5))
  137. [0, 1, 2, 3, 4]
  138. Verify that a gen exp cannot be resumed while it is actively running:
  139. >>> g = (me.next() for i in xrange(10))
  140. >>> me = g
  141. >>> me.next()
  142. Traceback (most recent call last):
  143. File "<pyshell#30>", line 1, in -toplevel-
  144. me.next()
  145. File "<pyshell#28>", line 1, in <generator expression>
  146. g = (me.next() for i in xrange(10))
  147. ValueError: generator already executing
  148. Verify exception propagation
  149. >>> g = (10 // i for i in (5, 0, 2))
  150. >>> g.next()
  151. 2
  152. >>> g.next()
  153. Traceback (most recent call last):
  154. File "<pyshell#37>", line 1, in -toplevel-
  155. g.next()
  156. File "<pyshell#35>", line 1, in <generator expression>
  157. g = (10 // i for i in (5, 0, 2))
  158. ZeroDivisionError: integer division or modulo by zero
  159. >>> g.next()
  160. Traceback (most recent call last):
  161. File "<pyshell#38>", line 1, in -toplevel-
  162. g.next()
  163. StopIteration
  164. Make sure that None is a valid return value
  165. >>> list(None for i in xrange(10))
  166. [None, None, None, None, None, None, None, None, None, None]
  167. Check that generator attributes are present
  168. >>> g = (i*i for i in range(3))
  169. >>> expected = set(['gi_frame', 'gi_running', 'next'])
  170. >>> set(attr for attr in dir(g) if not attr.startswith('__')) >= expected
  171. True
  172. >>> from test.test_support import HAVE_DOCSTRINGS
  173. >>> print(g.next.__doc__ if HAVE_DOCSTRINGS else 'x.next() -> the next value, or raise StopIteration')
  174. x.next() -> the next value, or raise StopIteration
  175. >>> import types
  176. >>> isinstance(g, types.GeneratorType)
  177. True
  178. Check the __iter__ slot is defined to return self
  179. >>> iter(g) is g
  180. True
  181. Verify that the running flag is set properly
  182. >>> g = (me.gi_running for i in (0,1))
  183. >>> me = g
  184. >>> me.gi_running
  185. 0
  186. >>> me.next()
  187. 1
  188. >>> me.gi_running
  189. 0
  190. Verify that genexps are weakly referencable
  191. >>> import weakref
  192. >>> g = (i*i for i in range(4))
  193. >>> wr = weakref.ref(g)
  194. >>> wr() is g
  195. True
  196. >>> p = weakref.proxy(g)
  197. >>> list(p)
  198. [0, 1, 4, 9]
  199. """
  200. __test__ = {'doctests' : doctests}
  201. def test_main(verbose=None):
  202. import sys
  203. from test import test_support
  204. from test import test_genexps
  205. test_support.run_doctest(test_genexps, verbose)
  206. # verify reference counting
  207. if verbose and hasattr(sys, "gettotalrefcount"):
  208. import gc
  209. counts = [None] * 5
  210. for i in xrange(len(counts)):
  211. test_support.run_doctest(test_genexps, verbose)
  212. gc.collect()
  213. counts[i] = sys.gettotalrefcount()
  214. print counts
  215. if __name__ == "__main__":
  216. test_main(verbose=True)