mirror of
https://github.com/AdaCore/cpython.git
synced 2026-02-12 12:57:15 -08:00
list comprehensions. see
http://sourceforge.net/patch/?func=detailpatch&patch_id=100654&group_id=5470 for details.
This commit is contained in:
@@ -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
|
||||
]
|
||||
|
||||
143
Python/compile.c
143
Python/compile.c
@@ -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)
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user