summaryrefslogtreecommitdiffstats
path: root/Lib/test
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2017-12-01 04:54:17 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2017-12-01 04:54:17 (GMT)
commit73a7e9b10b2ec9636e3c6396cf7b3695f8ed1856 (patch)
tree14101bd8c629aad1d3ae7cf77e1946516ddeba80 /Lib/test
parent6a89481680b921e7b317c29877bdda9a6031e5ad (diff)
downloadcpython-73a7e9b10b2ec9636e3c6396cf7b3695f8ed1856.zip
cpython-73a7e9b10b2ec9636e3c6396cf7b3695f8ed1856.tar.gz
cpython-73a7e9b10b2ec9636e3c6396cf7b3695f8ed1856.tar.bz2
bpo-10544: Deprecate "yield" in comprehensions and generator expressions. (GH-4579)
The current behaviour of yield expressions inside comprehensions and generator expressions is essentially an accident of implementation - it arises implicitly from the way the compiler handles yield expressions inside nested functions and generators. Since the current behaviour wasn't deliberately designed, and is inherently confusing, we're deprecating it, with no current plans to reintroduce it. Instead, our advice will be to use a named nested generator definition for cases where this behaviour is desired.
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_generators.py12
-rw-r--r--Lib/test/test_grammar.py35
2 files changed, 36 insertions, 11 deletions
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 7eac9d0..f88c762 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -1830,13 +1830,7 @@ Yield by itself yields None:
[None]
-
-An obscene abuse of a yield expression within a generator expression:
-
->>> list((yield 21) for i in range(4))
-[21, None, 21, None, 21, None, 21, None]
-
-And a more sane, but still weird usage:
+Yield is allowed only in the outermost iterable in generator expression:
>>> def f(): list(i for i in [(yield 26)])
>>> type(f())
@@ -2106,10 +2100,6 @@ enclosing function a generator:
>>> type(f())
<class 'generator'>
->>> def f(): x=(i for i in (yield) if (yield))
->>> type(f())
-<class 'generator'>
-
>>> def f(d): d[(yield "a")] = d[(yield "b")] = 27
>>> data = [1,2]
>>> g = f(data)
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 65e26bf..823315f 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -841,6 +841,41 @@ class GrammarTests(unittest.TestCase):
# Check annotation refleak on SyntaxError
check_syntax_error(self, "def g(a:(yield)): pass")
+ def test_yield_in_comprehensions(self):
+ # Check yield in comprehensions
+ def g(): [x for x in [(yield 1)]]
+ def g(): [x for x in [(yield from ())]]
+
+ def check(code, warntext):
+ with self.assertWarnsRegex(DeprecationWarning, warntext):
+ compile(code, '<test string>', 'exec')
+ import warnings
+ with warnings.catch_warnings():
+ warnings.filterwarnings('error', category=DeprecationWarning)
+ with self.assertRaisesRegex(SyntaxError, warntext):
+ compile(code, '<test string>', 'exec')
+
+ check("def g(): [(yield x) for x in ()]",
+ "'yield' inside list comprehension")
+ check("def g(): [x for x in () if not (yield x)]",
+ "'yield' inside list comprehension")
+ check("def g(): [y for x in () for y in [(yield x)]]",
+ "'yield' inside list comprehension")
+ check("def g(): {(yield x) for x in ()}",
+ "'yield' inside set comprehension")
+ check("def g(): {(yield x): x for x in ()}",
+ "'yield' inside dict comprehension")
+ check("def g(): {x: (yield x) for x in ()}",
+ "'yield' inside dict comprehension")
+ check("def g(): ((yield x) for x in ())",
+ "'yield' inside generator expression")
+ check("def g(): [(yield from x) for x in ()]",
+ "'yield' inside list comprehension")
+ check("class C: [(yield x) for x in ()]",
+ "'yield' inside list comprehension")
+ check("[(yield x) for x in ()]",
+ "'yield' inside list comprehension")
+
def test_raise(self):
# 'raise' test [',' test]
try: raise RuntimeError('just testing')