Commit dd090c34 authored by Skip Montanaro's avatar Skip Montanaro
parent be544c3f
......@@ -152,13 +152,22 @@ A list display is a possibly empty series of expressions enclosed in
square brackets:
\begin{verbatim}
list_display: "[" [expression_list] "]"
list_display: "[" [expression_list [list_iter]] "]"
list_iter: list_for | list_if
list_for: "for" expression_list "in" testlist [list_iter]
list_if: "if" test [list_iter]
\end{verbatim}
A list display yields a new list object. If it has no expression
list, the list object has no items. Otherwise, the elements of the
expression list are evaluated from left to right and inserted in the
list object in that order.
A list display yields a new list object. Its contents are specified
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
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
each time the innermost block is reached.
\obindex{list}
\indexii{empty}{list}
......
......@@ -1753,6 +1753,27 @@ item, then to the result and the next item, and so on. For example,
0
\end{verbatim}
\subsection{List Comprehensions}
List comprehensions provide a concise way to create lists without resorting
to use of the \func{map()} or \func{filter()} functions. The resulting
construct tends often to be clearer than use of those functions.
\begin{verbatim}
>>> spcs = [" Apple", " Banana ", "Coco nut "]
>>> print [s.strip() for s in spcs]
['Apple', 'Banana', 'Coco nut']
>>> vec = [2, 4, 6]
>>> print [3*x for x in vec]
[6, 12, 18]
>>> vec1 = [2, 4, 6]
>>> vec2 = [4, 3, -9]
>>> print [x*y for x in vec1 for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>> print [x+y for x in vec1 for y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
\end{verbatim}
\section{The \keyword{del} statement \label{del}}
There is a way to remove an item from a list given its index instead
......
......@@ -74,7 +74,8 @@ arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%') factor)*
factor: ('+'|'-'|'~') factor | power
power: atom trailer* ('**' factor)*
atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
listmaker: test ( list_iter | (',' test)* [','] )
lambdef: 'lambda' [varargslist] ':' test
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [',']
......@@ -88,3 +89,7 @@ classdef: 'class' NAME ['(' testlist ')'] ':' suite
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
argument: [test '='] test # Really [keyword '='] test
list_iter: list_for | list_if
list_for: 'for' exprlist 'in' testlist [list_iter]
list_if: 'if' test [list_iter]
......@@ -44,14 +44,18 @@
#define factor 299
#define power 300
#define atom 301
#define lambdef 302
#define trailer 303
#define subscriptlist 304
#define subscript 305
#define sliceop 306
#define exprlist 307
#define testlist 308
#define dictmaker 309
#define classdef 310
#define arglist 311
#define argument 312
#define listmaker 302
#define lambdef 303
#define trailer 304
#define subscriptlist 305
#define subscript 306
#define sliceop 307
#define exprlist 308
#define testlist 309
#define dictmaker 310
#define classdef 311
#define arglist 312
#define argument 313
#define list_iter 314
#define list_for 315
#define list_if 316
......@@ -45,3 +45,10 @@ selectors
atoms
classdef
['Apple', 'Banana', 'Coco nut']
[3, 6, 9, 12, 15]
[3, 4, 5]
[(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
[('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), ('Macdonalds', 'Cheeseburger')]
......@@ -542,3 +542,43 @@ class C:
def meth1(self): pass
def meth2(self, arg): pass
def meth3(self, a1, a2): pass
# list comprehension tests
nums = [1, 2, 3, 4, 5]
strs = ["Apple", "Banana", "Coconut"]
spcs = [" Apple", " Banana ", "Coco nut "]
print [s.strip() for s in spcs]
print [3 * x for x in nums]
print [x for x in nums if x > 2]
print [(i, s) for i in nums for s in strs]
print [(i, s) for i in nums for s in [f for f in strs if "n" in f]]
try:
eval("[i, s for i in nums for s in strs]")
print "FAIL: should have raised a SyntaxError!"
except SyntaxError:
print "good: got a SyntaxError as expected"
suppliers = [
(1, "Boeing"),
(2, "Ford"),
(3, "Macdonalds")
]
parts = [
(10, "Airliner"),
(20, "Engine"),
(30, "Cheeseburger")
]
suppart = [
(1, 10), (1, 20), (2, 20), (3, 30)
]
print [
(sname, pname)
for (sno, sname) in suppliers
for (pno, pname) in parts
for (sp_sno, sp_pno) in suppart
if sno == sp_sno and pno == sp_pno
]
......@@ -294,6 +294,7 @@ struct compiling {
#ifdef PRIVATE_NAME_MANGLING
char *c_private; /* for private name mangling */
#endif
int c_tmpname; /* temporary local name counter */
};
......@@ -368,8 +369,10 @@ static int com_addconst(struct compiling *, PyObject *);
static int com_addname(struct compiling *, PyObject *);
static void com_addopname(struct compiling *, int, node *);
static void com_list(struct compiling *, node *, int);
static void com_list_iter(struct compiling *, node *, node *, char *);
static int com_argdefs(struct compiling *, node *);
static int com_newlocal(struct compiling *, char *);
static void com_assign(struct compiling *, node *, int);
static PyCodeObject *icompile(struct _node *, struct compiling *);
static PyCodeObject *jcompile(struct _node *, char *,
struct compiling *);
......@@ -419,6 +422,7 @@ com_init(struct compiling *c, char *filename)
c->c_last_addr = 0;
c->c_last_line = 0;
c-> c_lnotab_next = 0;
c->c_tmpname = 0;
return 1;
fail:
......@@ -941,18 +945,116 @@ parsestrplus(node *n)
}
static void
com_list_constructor(struct compiling *c, node *n)
com_list_for(struct compiling *c, node *n, node *e, char *t)
{
int len;
int i;
if (TYPE(n) != testlist)
REQ(n, exprlist);
/* exprlist: expr (',' expr)* [',']; likewise for testlist */
len = (NCH(n) + 1) / 2;
for (i = 0; i < NCH(n); i += 2)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_LIST, len);
com_pop(c, len-1);
PyObject *v;
int anchor = 0;
int save_begin = c->c_begin;
/* list_iter: for v in expr [list_iter] */
com_node(c, CHILD(n, 3)); /* expr */
v = PyInt_FromLong(0L);
if (v == NULL)
c->c_errors++;
com_addoparg(c, LOAD_CONST, com_addconst(c, v));
com_push(c, 1);
Py_XDECREF(v);
c->c_begin = c->c_nexti;
com_addoparg(c, SET_LINENO, n->n_lineno);
com_addfwref(c, FOR_LOOP, &anchor);
com_push(c, 1);
com_assign(c, CHILD(n, 1), OP_ASSIGN);
c->c_loops++;
com_list_iter(c, n, e, t);
c->c_loops--;
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
c->c_begin = save_begin;
com_backpatch(c, anchor);
com_pop(c, 2); /* FOR_LOOP has popped these */
}
static void
com_list_if(struct compiling *c, node *n, node *e, char *t)
{
int anchor = 0;
int a = 0;
/* list_iter: 'if' test [list_iter] */
com_addoparg(c, SET_LINENO, n->n_lineno);
com_node(c, CHILD(n, 1));
com_addfwref(c, JUMP_IF_FALSE, &a);
com_addbyte(c, POP_TOP);
com_pop(c, 1);
com_list_iter(c, n, e, t);
com_addfwref(c, JUMP_FORWARD, &anchor);
com_backpatch(c, a);
/* We jump here with an extra entry which we now pop */
com_addbyte(c, POP_TOP);
com_backpatch(c, anchor);
}
static void
com_list_iter(struct compiling *c,
node *p, /* parent of list_iter node */
node *e, /* element expression node */
char *t /* name of result list temp local */)
{
/* list_iter is the last child in a listmaker, list_for, or list_if */
node *n = CHILD(p, NCH(p)-1);
if (TYPE(n) == list_iter) {
n = CHILD(n, 0);
switch (TYPE(n)) {
case list_for:
com_list_for(c, n, e, t);
break;
case list_if:
com_list_if(c, n, e, t);
break;
default:
com_error(c, PyExc_SystemError,
"invalid list_iter node type");
}
}
else {
com_addopnamestr(c, LOAD_NAME, t);
com_push(c, 1);
com_node(c, e);
com_addoparg(c, CALL_FUNCTION, 1);
com_addbyte(c, POP_TOP);
com_pop(c, 2);
}
}
static void
com_list_comprehension(struct compiling *c, node *n)
{
/* listmaker: test list_iter */
char tmpname[12];
sprintf(tmpname, "__%d__", ++c->c_tmpname);
com_addoparg(c, BUILD_LIST, 0);
com_addbyte(c, DUP_TOP); /* leave the result on the stack */
com_push(c, 2);
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_addopnamestr(c, DELETE_NAME, tmpname);
--c->c_tmpname;
}
static void
com_listmaker(struct compiling *c, node *n)
{
/* listmaker: test ( list_iter | (',' test)* [','] ) */
if (TYPE(CHILD(n, 1)) == list_iter)
com_list_comprehension(c, n);
else {
int len = 0;
int i;
for (i = 0; i < NCH(n); i += 2, len++)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_LIST, len);
com_pop(c, len-1);
}
}
static void
......@@ -990,18 +1092,18 @@ com_atom(struct compiling *c, node *n)
else
com_node(c, CHILD(n, 1));
break;
case LSQB:
case LSQB: /* '[' [listmaker] ']' */
if (TYPE(CHILD(n, 1)) == RSQB) {
com_addoparg(c, BUILD_LIST, 0);
com_push(c, 1);
}
else
com_list_constructor(c, CHILD(n, 1));
com_listmaker(c, CHILD(n, 1));
break;
case LBRACE: /* '{' [dictmaker] '}' */
com_addoparg(c, BUILD_MAP, 0);
com_push(c, 1);
if (TYPE(CHILD(n, 1)) != RBRACE)
if (TYPE(CHILD(n, 1)) == dictmaker)
com_dictmaker(c, CHILD(n, 1));
break;
case BACKQUOTE:
......@@ -1743,6 +1845,19 @@ com_assign_sequence(struct compiling *c, node *n, int assigning)
com_assign(c, CHILD(n, i), assigning);
}
static void
com_assign_list(struct compiling *c, node *n, int assigning)
{
int i;
if (assigning) {
i = (NCH(n)+1)/2;
com_addoparg(c, UNPACK_SEQUENCE, i);
com_push(c, i-1);
}
for (i = 0; i < NCH(n); i += 2)
com_assign(c, CHILD(n, i), assigning);
}
static void
com_assign_name(struct compiling *c, node *n, int assigning)
{
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment