require list comprehensions to start with a for clause

This commit is contained in:
Skip Montanaro 2000-08-22 02:43:07 +00:00
parent 2823f03a56
commit 46dfa5f4ed
7 changed files with 40 additions and 16 deletions

View File

@ -153,7 +153,7 @@ square brackets:
\begin{verbatim}
list_display: "[" [listmaker] "]"
listmaker: expression ( list_iter | ( "," expression)* [","] )
listmaker: expression ( list_for | ( "," expression)* [","] )
list_iter: list_for | list_if
list_for: "for" expression_list "in" testlist [list_iter]
list_if: "if" test [list_iter]
@ -164,7 +164,8 @@ by providing either a list of expressions or a list comprehension.
When a comma-separated list of expressions is supplied, its elements are
evaluated from left to right and placed into the list object in that
order. When a list comprehension is supplied, it consists of a
single expression followed by one or more "for" or "if" clauses. In this
single expression followed by at least one "for" clause and zero or more
"for" or "if" clauses. In this
case, the elements of the new list are those that would be produced
by considering each of the "for" or "if" clauses a block, nesting from
left to right, and evaluating the expression to produce a list element

View File

@ -1755,10 +1755,15 @@ item, then to the result and the next item, and so on. For example,
\subsection{List Comprehensions}
List comprehensions provide a concise way to create lists without
resorting to use of the \function{map()} or \function{filter()}
functions. The resulting construct tends often to be clearer than use
of those functions.
List comprehensions provide a concise way to create lists without resorting
to use of \function{map()}, \function{filter()} and/or \keyword{lambda}.
The resulting list definition tends often to be clearer than lists built
using those constructs. Each list comprehension consists of an expression
following by a \keyword{for} clause, then zero or more \keyword{for} or
\keyword{if} clauses. The result will be a list resulting from evaluating
the expression in the context of the \keyword{for} and \keyword{if} clauses
which follow it. If the expression would evaluate to a tuple, it must be
parenthesized.
\begin{verbatim}
>>> freshfruit = [' banana', ' loganberry ', 'passion fruit ']
@ -1771,6 +1776,17 @@ of those functions.
[12, 18]
>>> [3*x for x in vec if x < 2]
[]
>>> [{x: x**2} for x in vec]
[{2: 4}, {4: 16}, {6: 36}]
>>> [[x,x**2] for x in vec]
[[2, 4], [4, 16], [6, 36]]
>>> [x, x**2 for x in vec] # error - parens required for tuples
File "<stdin>", line 1
[x, x**2 for x in vec]
^
SyntaxError: invalid syntax
>>> [(x, x**2) for x in vec]
[(2, 4), (4, 16), (6, 36)]
>>> vec1 = [2, 4, 6]
>>> vec2 = [4, 3, -9]
>>> [x*y for x in vec1 for y in vec2]

View File

@ -77,7 +77,7 @@ term: factor (('*'|'/'|'%') factor)*
factor: ('+'|'-'|'~') factor | power
power: atom trailer* ('**' factor)*
atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
listmaker: test ( list_iter | (',' test)* [','] )
listmaker: test ( list_for | (',' test)* [','] )
lambdef: 'lambda' [varargslist] ':' test
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']

View File

@ -55,4 +55,5 @@ classdef
[(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]
[(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), (5, 'Banana'), (5, 'Coconut')]
good: got a SyntaxError as expected
good: got a SyntaxError as expected
[('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), ('Macdonalds', 'Cheeseburger')]

View File

@ -578,6 +578,12 @@ try:
except SyntaxError:
print "good: got a SyntaxError as expected"
try:
eval("[x if y]")
print "FAIL: should have raised a SyntaxError!"
except SyntaxError:
print "good: got a SyntaxError as expected"
suppliers = [
(1, "Boeing"),
(2, "Ford"),

View File

@ -1043,7 +1043,7 @@ com_list_iter(struct compiling *c,
static void
com_list_comprehension(struct compiling *c, node *n)
{
/* listmaker: test list_iter */
/* listmaker: test list_for */
char tmpname[12];
sprintf(tmpname, "__%d__", ++c->c_tmpname);
com_addoparg(c, BUILD_LIST, 0);
@ -1052,7 +1052,7 @@ com_list_comprehension(struct compiling *c, node *n)
com_addopnamestr(c, LOAD_ATTR, "append");
com_addopnamestr(c, STORE_NAME, tmpname);
com_pop(c, 1);
com_list_iter(c, n, CHILD(n, 0), tmpname);
com_list_for(c, CHILD(n, 1), CHILD(n, 0), tmpname);
com_addopnamestr(c, DELETE_NAME, tmpname);
--c->c_tmpname;
}
@ -1060,8 +1060,8 @@ com_list_comprehension(struct compiling *c, node *n)
static void
com_listmaker(struct compiling *c, node *n)
{
/* listmaker: test ( list_iter | (',' test)* [','] ) */
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_iter)
/* listmaker: test ( list_for | (',' test)* [','] ) */
if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == list_for)
com_list_comprehension(c, n);
else {
int len = 0;

View File

@ -1317,7 +1317,7 @@ static state states_59[4] = {
{1, arcs_59_3},
};
static arc arcs_60_0[2] = {
{128, 1},
{120, 1},
{129, 1},
};
static arc arcs_60_1[1] = {
@ -1340,7 +1340,7 @@ static arc arcs_61_3[1] = {
{9, 4},
};
static arc arcs_61_4[2] = {
{120, 5},
{128, 5},
{0, 4},
};
static arc arcs_61_5[1] = {
@ -1361,7 +1361,7 @@ static arc arcs_62_1[1] = {
{21, 2},
};
static arc arcs_62_2[2] = {
{120, 3},
{128, 3},
{0, 2},
};
static arc arcs_62_3[1] = {
@ -1622,7 +1622,7 @@ static label labels[130] = {
{25, 0},
{2, 0},
{3, 0},
{316, 0},
{317, 0},
{1, "lambda"},
{314, 0},
{307, 0},
@ -1630,7 +1630,7 @@ static label labels[130] = {
{309, 0},
{1, "class"},
{315, 0},
{317, 0},
{316, 0},
{318, 0},
};
grammar _PyParser_Grammar = {