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

Skip to content

Commit ba117ef

Browse files
committed
#4617: Previously it was illegal to delete a name from the local
namespace if it occurs as a free variable in a nested block. This limitation of the compiler has been lifted, and a new opcode introduced (DELETE_DEREF). This sample was valid in 2.6, but fails to compile in 3.x without this change:: >>> def f(): ... def print_error(): ... print(e) ... try: ... something ... except Exception as e: ... print_error() ... # implicit "del e" here This sample has always been invalid in Python, and now works:: >>> def outer(x): ... def inner(): ... return x ... inner() ... del x There is no need to bump the PYC magic number: the new opcode is used for code that did not compile before.
1 parent 4785916 commit ba117ef

12 files changed

Lines changed: 113 additions & 45 deletions

File tree

Doc/library/dis.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -723,6 +723,12 @@ the more significant byte last.
723723
storage.
724724

725725

726+
.. opcode:: DELETE_DEREF (i)
727+
728+
Empties the cell contained in slot *i* of the cell and free variable storage.
729+
Used by the :keyword:`del` statement.
730+
731+
726732
.. opcode:: SET_LINENO (lineno)
727733

728734
This opcode is obsolete.

Doc/reference/simple_stmts.rst

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -388,18 +388,17 @@ namespace, depending on whether the name occurs in a :keyword:`global` statement
388388
in the same code block. If the name is unbound, a :exc:`NameError` exception
389389
will be raised.
390390

391-
.. index:: pair: free; variable
392-
393-
It is illegal to delete a name from the local namespace if it occurs as a free
394-
variable in a nested block.
395-
396391
.. index:: pair: attribute; deletion
397392

398393
Deletion of attribute references, subscriptions and slicings is passed to the
399394
primary object involved; deletion of a slicing is in general equivalent to
400395
assignment of an empty slice of the right type (but even this is determined by
401396
the sliced object).
402397

398+
.. versionchanged:: 3.2
399+
Previously it was illegal to delete a name from the local namespace if it
400+
occurs as a free variable in a nested block.
401+
403402

404403
.. _return:
405404

Doc/whatsnew/3.2.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,31 @@ Some smaller changes made to the core Python language are:
240240

241241
(See :issue:`8188`.)
242242

243+
* Previously it was illegal to delete a name from the local namespace if it
244+
occurs as a free variable in a nested block::
245+
246+
>>> def outer(x):
247+
... def inner():
248+
... return x
249+
... inner()
250+
... del x
251+
252+
This is now allowed. Remember that the target of an :keyword:`except` clause
253+
is cleared, so this code which used to work with Python 2.6, raised a
254+
:exc:`SyntaxError` with Python 3.1 and now works again::
255+
256+
>>> def f():
257+
... def print_error():
258+
... print(e)
259+
... try:
260+
... something
261+
... except Exception as e:
262+
... print_error()
263+
... # implicit "del e" here
264+
265+
(See :issue:`4617`.)
266+
267+
243268
New, Improved, and Deprecated Modules
244269
=====================================
245270

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ extern "C" {
123123
#define LOAD_CLOSURE 135 /* Load free variable from closure */
124124
#define LOAD_DEREF 136 /* Load and dereference from closure cell */
125125
#define STORE_DEREF 137 /* Store into cell */
126+
#define DELETE_DEREF 138 /* Delete closure cell */
126127

127128
/* The next 3 opcodes must be contiguous and satisfy
128129
(CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1 */

Lib/opcode.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ def jabs_op(name, op):
161161
hasfree.append(136)
162162
def_op('STORE_DEREF', 137)
163163
hasfree.append(137)
164+
def_op('DELETE_DEREF', 138)
165+
hasfree.append(138)
164166

165167
def_op('CALL_FUNCTION_VAR', 140) # #args + (#kwargs << 8)
166168
def_op('CALL_FUNCTION_KW', 141) # #args + (#kwargs << 8)

Lib/test/test_exceptions.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,17 @@ def __exit__ (self, exc_type, exc_value, exc_tb):
526526
obj = wr()
527527
self.assertTrue(obj is None, "%s" % obj)
528528

529+
def test_exception_target_in_nested_scope(self):
530+
# issue 4617: This used to raise a SyntaxError
531+
# "can not delete variable 'e' referenced in nested scope"
532+
def print_error():
533+
e
534+
try:
535+
something
536+
except Exception as e:
537+
print_error()
538+
# implicit "del e" here
539+
529540
def test_generator_leaking(self):
530541
# Test that generator exception state doesn't leak into the calling
531542
# frame

Lib/test/test_scope.py

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,6 @@ def f(s):
217217
return f
218218
""")
219219

220-
check_syntax_error(self, """if 1:
221-
def f(x):
222-
def g():
223-
return x
224-
del x # can't del name
225-
""")
226-
227220
check_syntax_error(self, """if 1:
228221
def f():
229222
def g():
@@ -272,6 +265,28 @@ def inner():
272265
self.assertRaises(UnboundLocalError, errorInOuter)
273266
self.assertRaises(NameError, errorInInner)
274267

268+
def testUnboundLocal_AfterDel(self):
269+
# #4617: It is now legal to delete a cell variable.
270+
# The following functions must obviously compile,
271+
# and give the correct error when accessing the deleted name.
272+
def errorInOuter():
273+
y = 1
274+
del y
275+
print(y)
276+
def inner():
277+
return y
278+
279+
def errorInInner():
280+
def inner():
281+
return y
282+
y = 1
283+
del y
284+
inner()
285+
286+
self.assertRaises(UnboundLocalError, errorInOuter)
287+
self.assertRaises(NameError, errorInInner)
288+
289+
def testUnboundLocal_AugAssign(self):
275290
# test for bug #1501934: incorrect LOAD/STORE_GLOBAL generation
276291
exec("""if 1:
277292
global_x = 1

Lib/test/test_syntax.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -564,15 +564,6 @@ def warning():
564564
def test_break_outside_loop(self):
565565
self._check_error("break", "outside loop")
566566

567-
def test_delete_deref(self):
568-
source = """if 1:
569-
def foo(x):
570-
def bar():
571-
print(x)
572-
del x
573-
"""
574-
self._check_error(source, "nested scope")
575-
576567
def test_unexpected_indent(self):
577568
self._check_error("foo()\n bar()\n", "unexpected indent",
578569
subclass=IndentationError)

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 3.2 Alpha 3?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #4617: Previously it was illegal to delete a name from the local
14+
namespace if it occurs as a free variable in a nested block. This limitation
15+
of the compiler has been lifted, and a new opcode introduced (DELETE_DEREF).
16+
1317
- Issue #9804: ascii() now always represents unicode surrogate pairs as
1418
a single ``\UXXXXXXXX``, regardless of whether the character is printable
1519
or not. Also, the "backslashreplace" error handler now joins surrogate

Python/ceval.c

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ static PyObject * cmp_outcome(int, PyObject *, PyObject *);
135135
static PyObject * import_from(PyObject *, PyObject *);
136136
static int import_all_from(PyObject *, PyObject *);
137137
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
138+
static void format_exc_unbound(PyCodeObject *co, int oparg);
138139
static PyObject * unicode_concatenate(PyObject *, PyObject *,
139140
PyFrameObject *, unsigned char *);
140141
static PyObject * special_lookup(PyObject *, char *, PyObject **);
@@ -2143,6 +2144,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
21432144
);
21442145
break;
21452146

2147+
TARGET(DELETE_DEREF)
2148+
x = freevars[oparg];
2149+
if (PyCell_GET(x) != NULL) {
2150+
PyCell_Set(x, NULL);
2151+
continue;
2152+
}
2153+
err = -1;
2154+
format_exc_unbound(co, oparg);
2155+
break;
2156+
21462157
TARGET(LOAD_CLOSURE)
21472158
x = freevars[oparg];
21482159
Py_INCREF(x);
@@ -2158,22 +2169,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
21582169
DISPATCH();
21592170
}
21602171
err = -1;
2161-
/* Don't stomp existing exception */
2162-
if (PyErr_Occurred())
2163-
break;
2164-
if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
2165-
v = PyTuple_GET_ITEM(co->co_cellvars,
2166-
oparg);
2167-
format_exc_check_arg(
2168-
PyExc_UnboundLocalError,
2169-
UNBOUNDLOCAL_ERROR_MSG,
2170-
v);
2171-
} else {
2172-
v = PyTuple_GET_ITEM(co->co_freevars, oparg -
2173-
PyTuple_GET_SIZE(co->co_cellvars));
2174-
format_exc_check_arg(PyExc_NameError,
2175-
UNBOUNDFREE_ERROR_MSG, v);
2176-
}
2172+
format_exc_unbound(co, oparg);
21772173
break;
21782174

21792175
TARGET(STORE_DEREF)
@@ -4352,6 +4348,28 @@ format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj)
43524348
PyErr_Format(exc, format_str, obj_str);
43534349
}
43544350

4351+
static void
4352+
format_exc_unbound(PyCodeObject *co, int oparg)
4353+
{
4354+
PyObject *name;
4355+
/* Don't stomp existing exception */
4356+
if (PyErr_Occurred())
4357+
return;
4358+
if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
4359+
name = PyTuple_GET_ITEM(co->co_cellvars,
4360+
oparg);
4361+
format_exc_check_arg(
4362+
PyExc_UnboundLocalError,
4363+
UNBOUNDLOCAL_ERROR_MSG,
4364+
name);
4365+
} else {
4366+
name = PyTuple_GET_ITEM(co->co_freevars, oparg -
4367+
PyTuple_GET_SIZE(co->co_cellvars));
4368+
format_exc_check_arg(PyExc_NameError,
4369+
UNBOUNDFREE_ERROR_MSG, name);
4370+
}
4371+
}
4372+
43554373
static PyObject *
43564374
unicode_concatenate(PyObject *v, PyObject *w,
43574375
PyFrameObject *f, unsigned char *next_instr)

0 commit comments

Comments
 (0)