Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commitac66cc1

Browse files
authored
gh-104377: fix cell in comprehension that is free in outer scope (#104394)
1 parent37a5d25 commitac66cc1

File tree

2 files changed

+67
-7
lines changed

2 files changed

+67
-7
lines changed

‎Lib/test/test_listcomps.py‎

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ def get_output(moddict, name):
117117
newcode=code
118118
defget_output(moddict,name):
119119
returnmoddict[name]
120-
ns=nsor {}
120+
newns=ns.copy()ifnselse {}
121121
try:
122-
exec(newcode,ns)
122+
exec(newcode,newns)
123123
exceptraisesase:
124124
# We care about e.g. NameError vs UnboundLocalError
125125
self.assertIs(type(e),raises)
126126
else:
127127
fork,vin (outputsor {}).items():
128-
self.assertEqual(get_output(ns,k),v)
128+
self.assertEqual(get_output(newns,k),v)
129129

130130
deftest_lambdas_with_iteration_var_as_default(self):
131131
code="""
@@ -180,6 +180,26 @@ def test_closure_can_jump_over_comp_scope(self):
180180
z = [x() for x in items]
181181
"""
182182
outputs= {"z": [2,2,2,2,2]}
183+
self._check_in_scopes(code,outputs,scopes=["module","function"])
184+
185+
deftest_cell_inner_free_outer(self):
186+
code="""
187+
def f():
188+
return [lambda: x for x in (x, [1])[1]]
189+
x = ...
190+
y = [fn() for fn in f()]
191+
"""
192+
outputs= {"y": [1]}
193+
self._check_in_scopes(code,outputs,scopes=["module","function"])
194+
195+
deftest_free_inner_cell_outer(self):
196+
code="""
197+
g = 2
198+
def f():
199+
return g
200+
y = [g for x in [1]]
201+
"""
202+
outputs= {"y": [2]}
183203
self._check_in_scopes(code,outputs)
184204

185205
deftest_inner_cell_shadows_outer_redefined(self):
@@ -203,6 +223,37 @@ def inner():
203223
outputs= {"x":-1}
204224
self._check_in_scopes(code,outputs,ns={"g":-1})
205225

226+
deftest_explicit_global(self):
227+
code="""
228+
global g
229+
x = g
230+
g = 2
231+
items = [g for g in [1]]
232+
y = g
233+
"""
234+
outputs= {"x":1,"y":2,"items": [1]}
235+
self._check_in_scopes(code,outputs,ns={"g":1})
236+
237+
deftest_explicit_global_2(self):
238+
code="""
239+
global g
240+
x = g
241+
g = 2
242+
items = [g for x in [1]]
243+
y = g
244+
"""
245+
outputs= {"x":1,"y":2,"items": [2]}
246+
self._check_in_scopes(code,outputs,ns={"g":1})
247+
248+
deftest_explicit_global_3(self):
249+
code="""
250+
global g
251+
fns = [lambda: g for g in [2]]
252+
items = [fn() for fn in fns]
253+
"""
254+
outputs= {"items": [2]}
255+
self._check_in_scopes(code,outputs,ns={"g":1})
256+
206257
deftest_assignment_expression(self):
207258
code="""
208259
x = -1
@@ -250,7 +301,7 @@ def g():
250301
g()
251302
"""
252303
outputs= {"x":1}
253-
self._check_in_scopes(code,outputs)
304+
self._check_in_scopes(code,outputs,scopes=["module","function"])
254305

255306
deftest_introspecting_frame_locals(self):
256307
code="""

‎Python/compile.c‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5028,14 +5028,19 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
50285028
longscope= (symbol >>SCOPE_OFFSET)&SCOPE_MASK;
50295029
PyObject*outv=PyDict_GetItemWithError(c->u->u_ste->ste_symbols,k);
50305030
if (outv==NULL) {
5031+
assert(PyErr_Occurred());
50315032
returnERROR;
50325033
}
50335034
assert(PyLong_Check(outv));
50345035
longoutsc= (PyLong_AS_LONG(outv) >>SCOPE_OFFSET)&SCOPE_MASK;
5035-
if (scope!=outsc) {
5036+
if (scope!=outsc&& !(scope==CELL&&outsc==FREE)) {
50365037
// If a name has different scope inside than outside the
50375038
// comprehension, we need to temporarily handle it with the
5038-
// right scope while compiling the comprehension.
5039+
// right scope while compiling the comprehension. (If it's free
5040+
// in outer scope and cell in inner scope, we can't treat it as
5041+
// both cell and free in the same function, but treating it as
5042+
// free throughout is fine; it's *_DEREF either way.)
5043+
50395044
if (state->temp_symbols==NULL) {
50405045
state->temp_symbols=PyDict_New();
50415046
if (state->temp_symbols==NULL) {
@@ -5071,7 +5076,11 @@ push_inlined_comprehension_state(struct compiler *c, location loc,
50715076
// comprehension and restore the original one after
50725077
ADDOP_NAME(c,loc,LOAD_FAST_AND_CLEAR,k,varnames);
50735078
if (scope==CELL) {
5074-
ADDOP_NAME(c,loc,MAKE_CELL,k,cellvars);
5079+
if (outsc==FREE) {
5080+
ADDOP_NAME(c,loc,MAKE_CELL,k,freevars);
5081+
}else {
5082+
ADDOP_NAME(c,loc,MAKE_CELL,k,cellvars);
5083+
}
50755084
}
50765085
if (PyList_Append(state->pushed_locals,k)<0) {
50775086
returnERROR;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp