Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 803d6e5

Browse files
author
Skip Montanaro
committed
1 parent b16b835 commit 803d6e5

8 files changed

Lines changed: 528 additions & 232 deletions

File tree

Doc/ref/ref5.tex

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,22 @@ \subsection{List displays\label{lists}}
152152
square brackets:
153153

154154
\begin{verbatim}
155-
list_display: "[" [expression_list] "]"
155+
list_display: "[" [expression_list [list_iter]] "]"
156+
list_iter: list_for | list_if
157+
list_for: "for" expression_list "in" testlist [list_iter]
158+
list_if: "if" test [list_iter]
156159
\end{verbatim}
157160

158-
A list display yields a new list object. If it has no expression
159-
list, the list object has no items. Otherwise, the elements of the
160-
expression list are evaluated from left to right and inserted in the
161-
list object in that order.
161+
A list display yields a new list object. Its contents are specified
162+
by providing either a list of expressions or a list comprehension.
163+
When a comma-separated list of expressions is supplied, its elements are
164+
evaluated from left to right and placed into the list object in that
165+
order. When a list comprehension is supplied, it consists of a
166+
single expression followed by one or more "for" or "if" clauses. In this
167+
case, the elements of the new list are those that would be produced
168+
by considering each of the "for" or "if" clauses a block, nesting from
169+
left to right, and evaluating the expression to produce a list element
170+
each time the innermost block is reached.
162171
\obindex{list}
163172
\indexii{empty}{list}
164173

Doc/tut/tut.tex

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,6 +1753,27 @@ \subsection{Functional Programming Tools \label{functional}}
17531753
0
17541754
\end{verbatim}
17551755

1756+
\subsection{List Comprehensions}
1757+
1758+
List comprehensions provide a concise way to create lists without resorting
1759+
to use of the \func{map()} or \func{filter()} functions. The resulting
1760+
construct tends often to be clearer than use of those functions.
1761+
1762+
\begin{verbatim}
1763+
>>> spcs = [" Apple", " Banana ", "Coco nut "]
1764+
>>> print [s.strip() for s in spcs]
1765+
['Apple', 'Banana', 'Coco nut']
1766+
>>> vec = [2, 4, 6]
1767+
>>> print [3*x for x in vec]
1768+
[6, 12, 18]
1769+
>>> vec1 = [2, 4, 6]
1770+
>>> vec2 = [4, 3, -9]
1771+
>>> print [x*y for x in vec1 for y in vec2]
1772+
[8, 6, -18, 16, 12, -36, 24, 18, -54]
1773+
>>> print [x+y for x in vec1 for y in vec2]
1774+
[6, 5, -7, 8, 7, -5, 10, 9, -3]
1775+
\end{verbatim}
1776+
17561777
\section{The \keyword{del} statement \label{del}}
17571778

17581779
There is a way to remove an item from a list given its index instead

Grammar/Grammar

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ arith_expr: term (('+'|'-') term)*
7474
term: factor (('*'|'/'|'%') factor)*
7575
factor: ('+'|'-'|'~') factor | power
7676
power: atom trailer* ('**' factor)*
77-
atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
77+
atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
78+
listmaker: test ( list_iter | (',' test)* [','] )
7879
lambdef: 'lambda' [varargslist] ':' test
7980
trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
8081
subscriptlist: subscript (',' subscript)* [',']
@@ -88,3 +89,7 @@ classdef: 'class' NAME ['(' testlist ')'] ':' suite
8889

8990
arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test)
9091
argument: [test '='] test # Really [keyword '='] test
92+
93+
list_iter: list_for | list_if
94+
list_for: 'for' exprlist 'in' testlist [list_iter]
95+
list_if: 'if' test [list_iter]

Include/graminit.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@
4444
#define factor 299
4545
#define power 300
4646
#define atom 301
47-
#define lambdef 302
48-
#define trailer 303
49-
#define subscriptlist 304
50-
#define subscript 305
51-
#define sliceop 306
52-
#define exprlist 307
53-
#define testlist 308
54-
#define dictmaker 309
55-
#define classdef 310
56-
#define arglist 311
57-
#define argument 312
47+
#define listmaker 302
48+
#define lambdef 303
49+
#define trailer 304
50+
#define subscriptlist 305
51+
#define subscript 306
52+
#define sliceop 307
53+
#define exprlist 308
54+
#define testlist 309
55+
#define dictmaker 310
56+
#define classdef 311
57+
#define arglist 312
58+
#define argument 313
59+
#define list_iter 314
60+
#define list_for 315
61+
#define list_if 316

Lib/test/output/test_grammar

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,10 @@ selectors
4545

4646
atoms
4747
classdef
48+
['Apple', 'Banana', 'Coco nut']
49+
[3, 6, 9, 12, 15]
50+
[3, 4, 5]
51+
[(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')]
52+
[(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), (5, 'Banana'), (5, 'Coconut')]
53+
good: got a SyntaxError as expected
54+
[('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), ('Macdonalds', 'Cheeseburger')]

Lib/test/test_grammar.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -542,3 +542,43 @@ class C:
542542
def meth1(self): pass
543543
def meth2(self, arg): pass
544544
def meth3(self, a1, a2): pass
545+
546+
# list comprehension tests
547+
nums = [1, 2, 3, 4, 5]
548+
strs = ["Apple", "Banana", "Coconut"]
549+
spcs = [" Apple", " Banana ", "Coco nut "]
550+
551+
print [s.strip() for s in spcs]
552+
print [3 * x for x in nums]
553+
print [x for x in nums if x > 2]
554+
print [(i, s) for i in nums for s in strs]
555+
print [(i, s) for i in nums for s in [f for f in strs if "n" in f]]
556+
try:
557+
eval("[i, s for i in nums for s in strs]")
558+
print "FAIL: should have raised a SyntaxError!"
559+
except SyntaxError:
560+
print "good: got a SyntaxError as expected"
561+
562+
suppliers = [
563+
(1, "Boeing"),
564+
(2, "Ford"),
565+
(3, "Macdonalds")
566+
]
567+
568+
parts = [
569+
(10, "Airliner"),
570+
(20, "Engine"),
571+
(30, "Cheeseburger")
572+
]
573+
574+
suppart = [
575+
(1, 10), (1, 20), (2, 20), (3, 30)
576+
]
577+
578+
print [
579+
(sname, pname)
580+
for (sno, sname) in suppliers
581+
for (pno, pname) in parts
582+
for (sp_sno, sp_pno) in suppart
583+
if sno == sp_sno and pno == sp_pno
584+
]

Python/compile.c

Lines changed: 129 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ struct compiling {
294294
#ifdef PRIVATE_NAME_MANGLING
295295
char *c_private; /* for private name mangling */
296296
#endif
297+
int c_tmpname; /* temporary local name counter */
297298
};
298299

299300

@@ -368,8 +369,10 @@ static int com_addconst(struct compiling *, PyObject *);
368369
static int com_addname(struct compiling *, PyObject *);
369370
static void com_addopname(struct compiling *, int, node *);
370371
static void com_list(struct compiling *, node *, int);
372+
static void com_list_iter(struct compiling *, node *, node *, char *);
371373
static int com_argdefs(struct compiling *, node *);
372374
static int com_newlocal(struct compiling *, char *);
375+
static void com_assign(struct compiling *, node *, int);
373376
static PyCodeObject *icompile(struct _node *, struct compiling *);
374377
static PyCodeObject *jcompile(struct _node *, char *,
375378
struct compiling *);
@@ -419,6 +422,7 @@ com_init(struct compiling *c, char *filename)
419422
c->c_last_addr = 0;
420423
c->c_last_line = 0;
421424
c-> c_lnotab_next = 0;
425+
c->c_tmpname = 0;
422426
return 1;
423427

424428
fail:
@@ -941,18 +945,116 @@ parsestrplus(node *n)
941945
}
942946

943947
static void
944-
com_list_constructor(struct compiling *c, node *n)
948+
com_list_for(struct compiling *c, node *n, node *e, char *t)
945949
{
946-
int len;
947-
int i;
948-
if (TYPE(n) != testlist)
949-
REQ(n, exprlist);
950-
/* exprlist: expr (',' expr)* [',']; likewise for testlist */
951-
len = (NCH(n) + 1) / 2;
952-
for (i = 0; i < NCH(n); i += 2)
953-
com_node(c, CHILD(n, i));
954-
com_addoparg(c, BUILD_LIST, len);
955-
com_pop(c, len-1);
950+
PyObject *v;
951+
int anchor = 0;
952+
int save_begin = c->c_begin;
953+
954+
/* list_iter: for v in expr [list_iter] */
955+
com_node(c, CHILD(n, 3)); /* expr */
956+
v = PyInt_FromLong(0L);
957+
if (v == NULL)
958+
c->c_errors++;
959+
com_addoparg(c, LOAD_CONST, com_addconst(c, v));
960+
com_push(c, 1);
961+
Py_XDECREF(v);
962+
c->c_begin = c->c_nexti;
963+
com_addoparg(c, SET_LINENO, n->n_lineno);
964+
com_addfwref(c, FOR_LOOP, &anchor);
965+
com_push(c, 1);
966+
com_assign(c, CHILD(n, 1), OP_ASSIGN);
967+
c->c_loops++;
968+
com_list_iter(c, n, e, t);
969+
c->c_loops--;
970+
com_addoparg(c, JUMP_ABSOLUTE, c->c_begin);
971+
c->c_begin = save_begin;
972+
com_backpatch(c, anchor);
973+
com_pop(c, 2); /* FOR_LOOP has popped these */
974+
}
975+
976+
static void
977+
com_list_if(struct compiling *c, node *n, node *e, char *t)
978+
{
979+
int anchor = 0;
980+
int a = 0;
981+
/* list_iter: 'if' test [list_iter] */
982+
com_addoparg(c, SET_LINENO, n->n_lineno);
983+
com_node(c, CHILD(n, 1));
984+
com_addfwref(c, JUMP_IF_FALSE, &a);
985+
com_addbyte(c, POP_TOP);
986+
com_pop(c, 1);
987+
com_list_iter(c, n, e, t);
988+
com_addfwref(c, JUMP_FORWARD, &anchor);
989+
com_backpatch(c, a);
990+
/* We jump here with an extra entry which we now pop */
991+
com_addbyte(c, POP_TOP);
992+
com_backpatch(c, anchor);
993+
}
994+
995+
static void
996+
com_list_iter(struct compiling *c,
997+
node *p, /* parent of list_iter node */
998+
node *e, /* element expression node */
999+
char *t /* name of result list temp local */)
1000+
{
1001+
/* list_iter is the last child in a listmaker, list_for, or list_if */
1002+
node *n = CHILD(p, NCH(p)-1);
1003+
if (TYPE(n) == list_iter) {
1004+
n = CHILD(n, 0);
1005+
switch (TYPE(n)) {
1006+
case list_for:
1007+
com_list_for(c, n, e, t);
1008+
break;
1009+
case list_if:
1010+
com_list_if(c, n, e, t);
1011+
break;
1012+
default:
1013+
com_error(c, PyExc_SystemError,
1014+
"invalid list_iter node type");
1015+
}
1016+
}
1017+
else {
1018+
com_addopnamestr(c, LOAD_NAME, t);
1019+
com_push(c, 1);
1020+
com_node(c, e);
1021+
com_addoparg(c, CALL_FUNCTION, 1);
1022+
com_addbyte(c, POP_TOP);
1023+
com_pop(c, 2);
1024+
}
1025+
}
1026+
1027+
static void
1028+
com_list_comprehension(struct compiling *c, node *n)
1029+
{
1030+
/* listmaker: test list_iter */
1031+
char tmpname[12];
1032+
sprintf(tmpname, "__%d__", ++c->c_tmpname);
1033+
com_addoparg(c, BUILD_LIST, 0);
1034+
com_addbyte(c, DUP_TOP); /* leave the result on the stack */
1035+
com_push(c, 2);
1036+
com_addopnamestr(c, LOAD_ATTR, "append");
1037+
com_addopnamestr(c, STORE_NAME, tmpname);
1038+
com_pop(c, 1);
1039+
com_list_iter(c, n, CHILD(n, 0), tmpname);
1040+
com_addopnamestr(c, DELETE_NAME, tmpname);
1041+
--c->c_tmpname;
1042+
}
1043+
1044+
static void
1045+
com_listmaker(struct compiling *c, node *n)
1046+
{
1047+
/* listmaker: test ( list_iter | (',' test)* [','] ) */
1048+
if (TYPE(CHILD(n, 1)) == list_iter)
1049+
com_list_comprehension(c, n);
1050+
else {
1051+
int len = 0;
1052+
int i;
1053+
for (i = 0; i < NCH(n); i += 2, len++)
1054+
com_node(c, CHILD(n, i));
1055+
com_addoparg(c, BUILD_LIST, len);
1056+
com_pop(c, len-1);
1057+
}
9561058
}
9571059

9581060
static void
@@ -990,18 +1092,18 @@ com_atom(struct compiling *c, node *n)
9901092
else
9911093
com_node(c, CHILD(n, 1));
9921094
break;
993-
case LSQB:
1095+
case LSQB: /* '[' [listmaker] ']' */
9941096
if (TYPE(CHILD(n, 1)) == RSQB) {
9951097
com_addoparg(c, BUILD_LIST, 0);
9961098
com_push(c, 1);
9971099
}
9981100
else
999-
com_list_constructor(c, CHILD(n, 1));
1101+
com_listmaker(c, CHILD(n, 1));
10001102
break;
10011103
case LBRACE: /* '{' [dictmaker] '}' */
10021104
com_addoparg(c, BUILD_MAP, 0);
10031105
com_push(c, 1);
1004-
if (TYPE(CHILD(n, 1)) != RBRACE)
1106+
if (TYPE(CHILD(n, 1)) == dictmaker)
10051107
com_dictmaker(c, CHILD(n, 1));
10061108
break;
10071109
case BACKQUOTE:
@@ -1743,6 +1845,19 @@ com_assign_sequence(struct compiling *c, node *n, int assigning)
17431845
com_assign(c, CHILD(n, i), assigning);
17441846
}
17451847

1848+
static void
1849+
com_assign_list(struct compiling *c, node *n, int assigning)
1850+
{
1851+
int i;
1852+
if (assigning) {
1853+
i = (NCH(n)+1)/2;
1854+
com_addoparg(c, UNPACK_SEQUENCE, i);
1855+
com_push(c, i-1);
1856+
}
1857+
for (i = 0; i < NCH(n); i += 2)
1858+
com_assign(c, CHILD(n, i), assigning);
1859+
}
1860+
17461861
static void
17471862
com_assign_name(struct compiling *c, node *n, int assigning)
17481863
{

0 commit comments

Comments
 (0)