Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 22547d4

Browse filesBrowse files
committed
Implement early binding of comprehension variables in class scope
1 parent a63b584 commit 22547d4
Copy full SHA for 22547d4

File tree

Expand file treeCollapse file tree

3 files changed

+52
-2
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+52
-2
lines changed

‎Include/symtable.h

Copy file name to clipboardExpand all lines: Include/symtable.h
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ typedef struct _symtable_entry {
4242
PyObject *ste_varnames; /* list of function parameters */
4343
PyObject *ste_children; /* list of child blocks */
4444
PyObject *ste_directives;/* locations of global and nonlocal statements */
45+
PyObject *ste_classsyms; /* ste_symbols for the surrounding class of a comprehension */
4546
_Py_block_ty ste_type; /* module, class, or function */
4647
int ste_nested; /* true if block is nested */
4748
unsigned ste_free : 1; /* true if block has free variables */
@@ -92,6 +93,7 @@ PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
9293
#define DEF_FREE_CLASS 2<<5 /* free variable from class's method */
9394
#define DEF_IMPORT 2<<6 /* assignment occurred via import */
9495
#define DEF_ANNOT 2<<7 /* this name is annotated */
96+
#define DEF_EARLYBIND 2<<8 /* name requires early binding semantics (via function args) */
9597

9698
#define DEF_BOUND (DEF_LOCAL | DEF_PARAM | DEF_IMPORT)
9799

‎Python/compile.c

Copy file name to clipboardExpand all lines: Python/compile.c
+28-2Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3886,10 +3886,12 @@ compiler_sync_comprehension_generator(struct compiler *c,
38863886
return 0;
38873887

38883888
gen = (comprehension_ty)asdl_seq_GET(generators, gen_index);
3889-
38903889
if (gen_index == 0) {
38913890
/* Receive outermost iter as an implicit argument */
38923891
c->u->u_argcount = 1;
3892+
/* In some cases, receive additional arguments */
3893+
if (c->u->u_ste->ste_classsyms)
3894+
c->u->u_argcount = PyList_Size(c->u->u_ste->ste_varnames);
38933895
ADDOP_I(c, LOAD_FAST, 0);
38943896
}
38953897
else {
@@ -4106,6 +4108,13 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
41064108
co = assemble(c, 1);
41074109
qualname = c->u->u_qualname;
41084110
Py_INCREF(qualname);
4111+
Py_ssize_t args = 1;
4112+
PyObject *varnames = NULL, *symbols = NULL;
4113+
if (c->u->u_ste->ste_classsyms) {
4114+
args = c->u->u_argcount;
4115+
varnames = c->u->u_ste->ste_varnames; Py_INCREF(varnames);
4116+
symbols = c->u->u_ste->ste_symbols; Py_INCREF(symbols);
4117+
}
41094118
compiler_exit_scope(c);
41104119
if (co == NULL)
41114120
goto error;
@@ -4123,7 +4132,24 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
41234132
ADDOP(c, GET_ITER);
41244133
}
41254134

4126-
ADDOP_I(c, CALL_FUNCTION, 1);
4135+
/* Load up the early-bound names */
4136+
if (varnames) {
4137+
Py_ssize_t sz = PyList_Size(varnames);
4138+
Py_ssize_t i;
4139+
for (i = 1; i < sz; ++i) {
4140+
PyObject *name = PyList_GetItem(varnames, i);
4141+
PyObject *v = PyDict_GetItem(symbols, name);
4142+
long flags = 0; if (v) flags = PyLong_AS_LONG(v);
4143+
if (flags & DEF_EARLYBIND)
4144+
compiler_nameop(c, name, Load);
4145+
else
4146+
ADDOP_O(c, LOAD_CONST, Py_None, consts);
4147+
}
4148+
}
4149+
else args = 1;
4150+
Py_XDECREF(varnames); Py_XDECREF(symbols);
4151+
4152+
ADDOP_I(c, CALL_FUNCTION, args);
41274153

41284154
if (is_async_generator && type != COMP_GENEXP) {
41294155
ADDOP(c, GET_AWAITABLE);

‎Python/symtable.c

Copy file name to clipboardExpand all lines: Python/symtable.c
+22Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ ste_new(struct symtable *st, identifier name, _Py_block_ty block,
5959
ste->ste_symbols = NULL;
6060
ste->ste_varnames = NULL;
6161
ste->ste_children = NULL;
62+
ste->ste_classsyms = NULL;
6263

6364
ste->ste_directives = NULL;
6465

@@ -1484,6 +1485,21 @@ symtable_visit_expr(struct symtable *st, expr_ty e)
14841485
VISIT(st, expr, e->v.Starred.value);
14851486
break;
14861487
case Name_kind:
1488+
if (e->v.Name.ctx == Load && st->st_cur->ste_classsyms) {
1489+
long localflags = 0, classflags = 0;
1490+
PyObject *v = PyDict_GetItem(st->st_cur->ste_symbols, e->v.Name.id);
1491+
if (v) localflags = PyLong_AsLong(v);
1492+
v = PyDict_GetItem(st->st_cur->ste_classsyms, e->v.Name.id);
1493+
if (v) classflags = PyLong_AsLong(v);
1494+
/* If the name has not (yet) been assigned to in this scope, AND it
1495+
has been assigned to in the surrounding scope, flag it Early Bind. */
1496+
if (!(localflags & DEF_LOCAL) && (classflags & DEF_LOCAL)) {
1497+
PyObject *val = PyLong_FromLong(localflags | DEF_PARAM | DEF_EARLYBIND);
1498+
PyDict_SetItem(st->st_cur->ste_symbols, e->v.Name.id, val);
1499+
Py_DECREF(val);
1500+
PyList_Append(st->st_cur->ste_varnames, e->v.Name.id);
1501+
}
1502+
}
14871503
if (!symtable_add_def(st, e->v.Name.id,
14881504
e->v.Name.ctx == Load ? USE : DEF_LOCAL))
14891505
VISIT_QUIT(st, 0);
@@ -1710,6 +1726,11 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
17101726
int is_generator = (e->kind == GeneratorExp_kind);
17111727
comprehension_ty outermost = ((comprehension_ty)
17121728
asdl_seq_GET(generators, 0));
1729+
PyObject *classsyms = NULL;
1730+
if (st->st_cur->ste_type == ClassBlock) {
1731+
/* Flag this as a comprehension in a class, with potential for early binding */
1732+
classsyms = st->st_cur->ste_symbols;
1733+
}
17131734
/* Outermost iterator is evaluated in current scope */
17141735
VISIT(st, expr, outermost->iter);
17151736
/* Create comprehension scope for the rest */
@@ -1718,6 +1739,7 @@ symtable_handle_comprehension(struct symtable *st, expr_ty e,
17181739
e->lineno, e->col_offset)) {
17191740
return 0;
17201741
}
1742+
st->st_cur->ste_classsyms = classsyms;
17211743
if (outermost->is_async) {
17221744
st->st_cur->ste_coroutine = 1;
17231745
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.