mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
Bug #1520864 (again): unpacking singleton tuples in list comprehensions and
generator expressions (x for x, in ... ) works again. Sigh, I only fixed for loops the first time, not list comps and genexprs too. I couldn't find any more unpacking cases where there is a similar bug lurking. This code should be refactored to eliminate the duplication. I'm sure the listcomp/genexpr code can be refactored. I'm not sure if the for loop can re-use any of the same code though. Will backport to 2.5 (the only place it matters).
This commit is contained in:
parent
4bc2c0919b
commit
dac090d3e6
4 changed files with 23 additions and 5 deletions
|
@ -825,6 +825,10 @@ verify([(i,j) for i in range(10) for j in range(5)] == list(g))
|
||||||
verify([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7])
|
verify([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7])
|
||||||
verify((x for x in range(10) if x % 2 if x % 3), [1, 5, 7])
|
verify((x for x in range(10) if x % 2 if x % 3), [1, 5, 7])
|
||||||
|
|
||||||
|
# Verify unpacking single element tuples in listcomp/genexp.
|
||||||
|
vereq([x for x, in [(4,), (5,), (6,)]], [4, 5, 6])
|
||||||
|
vereq(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9])
|
||||||
|
|
||||||
# Test ifelse expressions in various cases
|
# Test ifelse expressions in various cases
|
||||||
def _checkeval(msg, ret):
|
def _checkeval(msg, ret):
|
||||||
"helper to check that evaluation of expressions is done correctly"
|
"helper to check that evaluation of expressions is done correctly"
|
||||||
|
|
|
@ -22,6 +22,11 @@ Core and builtins
|
||||||
- The return tuple from str.rpartition(sep) is (tail, sep, head) where
|
- The return tuple from str.rpartition(sep) is (tail, sep, head) where
|
||||||
head is the original string if sep was not found.
|
head is the original string if sep was not found.
|
||||||
|
|
||||||
|
- Bug #1520864: unpacking singleton tuples in list comprehensions and
|
||||||
|
generator expressions (x for x, in ... ) works again. Fixing this problem
|
||||||
|
required changing the .pyc magic number. This means that .pyc files
|
||||||
|
generated before 2.5c2 will be regenerated.
|
||||||
|
|
||||||
|
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
16
Python/ast.c
16
Python/ast.c
|
@ -983,17 +983,21 @@ ast_for_listcomp(struct compiling *c, const node *n)
|
||||||
comprehension_ty lc;
|
comprehension_ty lc;
|
||||||
asdl_seq *t;
|
asdl_seq *t;
|
||||||
expr_ty expression;
|
expr_ty expression;
|
||||||
|
node *for_ch;
|
||||||
|
|
||||||
REQ(ch, list_for);
|
REQ(ch, list_for);
|
||||||
|
|
||||||
t = ast_for_exprlist(c, CHILD(ch, 1), Store);
|
for_ch = CHILD(ch, 1);
|
||||||
|
t = ast_for_exprlist(c, for_ch, Store);
|
||||||
if (!t)
|
if (!t)
|
||||||
return NULL;
|
return NULL;
|
||||||
expression = ast_for_testlist(c, CHILD(ch, 3));
|
expression = ast_for_testlist(c, CHILD(ch, 3));
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (asdl_seq_LEN(t) == 1)
|
/* Check the # of children rather than the length of t, since
|
||||||
|
[x for x, in ... ] has 1 element in t, but still requires a Tuple. */
|
||||||
|
if (NCH(for_ch) == 1)
|
||||||
lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL,
|
lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL,
|
||||||
c->c_arena);
|
c->c_arena);
|
||||||
else
|
else
|
||||||
|
@ -1129,17 +1133,21 @@ ast_for_genexp(struct compiling *c, const node *n)
|
||||||
comprehension_ty ge;
|
comprehension_ty ge;
|
||||||
asdl_seq *t;
|
asdl_seq *t;
|
||||||
expr_ty expression;
|
expr_ty expression;
|
||||||
|
node *for_ch;
|
||||||
|
|
||||||
REQ(ch, gen_for);
|
REQ(ch, gen_for);
|
||||||
|
|
||||||
t = ast_for_exprlist(c, CHILD(ch, 1), Store);
|
for_ch = CHILD(ch, 1);
|
||||||
|
t = ast_for_exprlist(c, for_ch, Store);
|
||||||
if (!t)
|
if (!t)
|
||||||
return NULL;
|
return NULL;
|
||||||
expression = ast_for_expr(c, CHILD(ch, 3));
|
expression = ast_for_expr(c, CHILD(ch, 3));
|
||||||
if (!expression)
|
if (!expression)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (asdl_seq_LEN(t) == 1)
|
/* Check the # of children rather than the length of t, since
|
||||||
|
(x for x, in ...) has 1 element in t, but still requires a Tuple. */
|
||||||
|
if (NCH(for_ch) == 1)
|
||||||
ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression,
|
ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression,
|
||||||
NULL, c->c_arena);
|
NULL, c->c_arena);
|
||||||
else
|
else
|
||||||
|
|
|
@ -64,9 +64,10 @@ extern time_t PyOS_GetLastModificationTime(char *, FILE *);
|
||||||
Python 2.5b3: 62111 (fix wrong code: x += yield)
|
Python 2.5b3: 62111 (fix wrong code: x += yield)
|
||||||
Python 2.5c1: 62121 (fix wrong lnotab with for loops and
|
Python 2.5c1: 62121 (fix wrong lnotab with for loops and
|
||||||
storing constants that should have been removed)
|
storing constants that should have been removed)
|
||||||
|
Python 2.5c2: 62131 (fix wrong code: for x, in ... in listcomp/genexp)
|
||||||
.
|
.
|
||||||
*/
|
*/
|
||||||
#define MAGIC (62121 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
#define MAGIC (62131 | ((long)'\r'<<16) | ((long)'\n'<<24))
|
||||||
|
|
||||||
/* Magic word as global; note that _PyImport_Init() can change the
|
/* Magic word as global; note that _PyImport_Init() can change the
|
||||||
value of this global to accommodate for alterations of how the
|
value of this global to accommodate for alterations of how the
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue