Change the semantics of "return" in generators, as discussed on the
Iterators list and Python-Dev; e.g., these all pass now:
def g1():
try:
return
except:
yield 1
assert list(g1()) == []
def g2():
try:
return
finally:
yield 1
assert list(g2()) == [1]
def g3():
for i in range(3):
yield None
yield None
assert list(g3()) == [None] * 4
compile.c: compile_funcdef and com_return_stmt: Just van Rossum's patch
to compile the same code for "return" regardless of function type (this
goes back to the previous scheme of returning Py_None).
ceval.c: gen_iternext: take a return (but not a yield) of Py_None as
meaning the generator is exhausted.
diff --git a/Python/ceval.c b/Python/ceval.c
index d334775..6a1ba50 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -166,6 +166,13 @@
Py_XDECREF(f->f_back);
f->f_back = NULL;
+ /* If the generator just returned (as opposed to yielding), signal
+ * that the generator is exhausted. */
+ if (result == Py_None && f->f_stacktop == NULL) {
+ Py_DECREF(result);
+ result = NULL;
+ }
+
return result;
}
diff --git a/Python/compile.c b/Python/compile.c
index 843cf09..2ce7487 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -2639,20 +2639,14 @@
com_error(c, PyExc_SyntaxError,
"'return' with argument inside generator");
}
- com_addoparg(c, LOAD_CONST,
- com_addconst(c, PyExc_StopIteration));
+ }
+ if (NCH(n) < 2) {
+ com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
com_push(c, 1);
- com_addoparg(c, RAISE_VARARGS, 1);
}
- else {
- if (NCH(n) < 2) {
- com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
- com_push(c, 1);
- }
- else
- com_node(c, CHILD(n, 1));
- com_addbyte(c, RETURN_VALUE);
- }
+ else
+ com_node(c, CHILD(n, 1));
+ com_addbyte(c, RETURN_VALUE);
com_pop(c, 1);
}
@@ -3711,19 +3705,10 @@
c->c_infunction = 1;
com_node(c, CHILD(n, 4));
c->c_infunction = 0;
- if (c->c_flags & CO_GENERATOR) {
- com_addoparg(c, LOAD_CONST,
- com_addconst(c, PyExc_StopIteration));
- com_push(c, 1);
- com_addoparg(c, RAISE_VARARGS, 1);
- com_pop(c, 1);
- }
- else {
- com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
- com_push(c, 1);
- com_addbyte(c, RETURN_VALUE);
- com_pop(c, 1);
- }
+ com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None));
+ com_push(c, 1);
+ com_addbyte(c, RETURN_VALUE);
+ com_pop(c, 1);
}
static void