Kaydet (Commit) 803d6e54 authored tarafından Skip Montanaro's avatar Skip Montanaro
üst b16b8353
...@@ -152,13 +152,22 @@ A list display is a possibly empty series of expressions enclosed in ...@@ -152,13 +152,22 @@ A list display is a possibly empty series of expressions enclosed in
square brackets: square brackets:
\begin{verbatim} \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} \end{verbatim}
A list display yields a new list object. If it has no expression A list display yields a new list object. Its contents are specified
list, the list object has no items. Otherwise, the elements of the by providing either a list of expressions or a list comprehension.
expression list are evaluated from left to right and inserted in the When a comma-separated list of expressions is supplied, its elements are
list object in that order. 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} \obindex{list}
\indexii{empty}{list} \indexii{empty}{list}
......
...@@ -1753,6 +1753,27 @@ item, then to the result and the next item, and so on. For example, ...@@ -1753,6 +1753,27 @@ item, then to the result and the next item, and so on. For example,
0 0
\end{verbatim} \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}} \section{The \keyword{del} statement \label{del}}
There is a way to remove an item from a list given its index instead There is a way to remove an item from a list given its index instead
......
...@@ -74,7 +74,8 @@ arith_expr: term (('+'|'-') term)* ...@@ -74,7 +74,8 @@ arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%') factor)* term: factor (('*'|'/'|'%') factor)*
factor: ('+'|'-'|'~') factor | power factor: ('+'|'-'|'~') factor | power
power: atom trailer* ('**' factor)* 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 lambdef: 'lambda' [varargslist] ':' test
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
subscriptlist: subscript (',' subscript)* [','] subscriptlist: subscript (',' subscript)* [',']
...@@ -88,3 +89,7 @@ classdef: 'class' NAME ['(' testlist ')'] ':' suite ...@@ -88,3 +89,7 @@ classdef: 'class' NAME ['(' testlist ')'] ':' suite
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
argument: [test '='] test # Really [keyword '='] 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 @@ ...@@ -44,14 +44,18 @@
#define factor 299 #define factor 299
#define power 300 #define power 300
#define atom 301 #define atom 301
#define lambdef 302 #define listmaker 302
#define trailer 303 #define lambdef 303
#define subscriptlist 304 #define trailer 304
#define subscript 305 #define subscriptlist 305
#define sliceop 306 #define subscript 306
#define exprlist 307 #define sliceop 307
#define testlist 308 #define exprlist 308
#define dictmaker 309 #define testlist 309
#define classdef 310 #define dictmaker 310
#define arglist 311 #define classdef 311
#define argument 312 #define arglist 312
#define argument 313
#define list_iter 314
#define list_for 315
#define list_if 316
...@@ -45,3 +45,10 @@ selectors ...@@ -45,3 +45,10 @@ selectors
atoms atoms
classdef 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: ...@@ -542,3 +542,43 @@ class C:
def meth1(self): pass def meth1(self): pass
def meth2(self, arg): pass def meth2(self, arg): pass
def meth3(self, a1, a2): 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 { ...@@ -294,6 +294,7 @@ struct compiling {
#ifdef PRIVATE_NAME_MANGLING #ifdef PRIVATE_NAME_MANGLING
char *c_private; /* for private name mangling */ char *c_private; /* for private name mangling */
#endif #endif
int c_tmpname; /* temporary local name counter */
}; };
...@@ -368,8 +369,10 @@ static int com_addconst(struct compiling *, PyObject *); ...@@ -368,8 +369,10 @@ static int com_addconst(struct compiling *, PyObject *);
static int com_addname(struct compiling *, PyObject *); static int com_addname(struct compiling *, PyObject *);
static void com_addopname(struct compiling *, int, node *); static void com_addopname(struct compiling *, int, node *);
static void com_list(struct compiling *, node *, int); 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_argdefs(struct compiling *, node *);
static int com_newlocal(struct compiling *, char *); static int com_newlocal(struct compiling *, char *);
static void com_assign(struct compiling *, node *, int);
static PyCodeObject *icompile(struct _node *, struct compiling *); static PyCodeObject *icompile(struct _node *, struct compiling *);
static PyCodeObject *jcompile(struct _node *, char *, static PyCodeObject *jcompile(struct _node *, char *,
struct compiling *); struct compiling *);
...@@ -419,6 +422,7 @@ com_init(struct compiling *c, char *filename) ...@@ -419,6 +422,7 @@ com_init(struct compiling *c, char *filename)
c->c_last_addr = 0; c->c_last_addr = 0;
c->c_last_line = 0; c->c_last_line = 0;
c-> c_lnotab_next = 0; c-> c_lnotab_next = 0;
c->c_tmpname = 0;
return 1; return 1;
fail: fail:
...@@ -941,18 +945,116 @@ parsestrplus(node *n) ...@@ -941,18 +945,116 @@ parsestrplus(node *n)
} }
static void static void
com_list_constructor(struct compiling *c, node *n) com_list_for(struct compiling *c, node *n, node *e, char *t)
{ {
int len; PyObject *v;
int i; int anchor = 0;
if (TYPE(n) != testlist) int save_begin = c->c_begin;
REQ(n, exprlist);
/* exprlist: expr (',' expr)* [',']; likewise for testlist */ /* list_iter: for v in expr [list_iter] */
len = (NCH(n) + 1) / 2; com_node(c, CHILD(n, 3)); /* expr */
for (i = 0; i < NCH(n); i += 2) v = PyInt_FromLong(0L);
com_node(c, CHILD(n, i)); if (v == NULL)
com_addoparg(c, BUILD_LIST, len); c->c_errors++;
com_pop(c, len-1); 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 static void
...@@ -990,18 +1092,18 @@ com_atom(struct compiling *c, node *n) ...@@ -990,18 +1092,18 @@ com_atom(struct compiling *c, node *n)
else else
com_node(c, CHILD(n, 1)); com_node(c, CHILD(n, 1));
break; break;
case LSQB: case LSQB: /* '[' [listmaker] ']' */
if (TYPE(CHILD(n, 1)) == RSQB) { if (TYPE(CHILD(n, 1)) == RSQB) {
com_addoparg(c, BUILD_LIST, 0); com_addoparg(c, BUILD_LIST, 0);
com_push(c, 1); com_push(c, 1);
} }
else else
com_list_constructor(c, CHILD(n, 1)); com_listmaker(c, CHILD(n, 1));
break; break;
case LBRACE: /* '{' [dictmaker] '}' */ case LBRACE: /* '{' [dictmaker] '}' */
com_addoparg(c, BUILD_MAP, 0); com_addoparg(c, BUILD_MAP, 0);
com_push(c, 1); com_push(c, 1);
if (TYPE(CHILD(n, 1)) != RBRACE) if (TYPE(CHILD(n, 1)) == dictmaker)
com_dictmaker(c, CHILD(n, 1)); com_dictmaker(c, CHILD(n, 1));
break; break;
case BACKQUOTE: case BACKQUOTE:
...@@ -1743,6 +1845,19 @@ com_assign_sequence(struct compiling *c, node *n, int assigning) ...@@ -1743,6 +1845,19 @@ com_assign_sequence(struct compiling *c, node *n, int assigning)
com_assign(c, CHILD(n, i), 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 static void
com_assign_name(struct compiling *c, node *n, int assigning) 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