Kaydet (Commit) 87460821 authored tarafından Guido van Rossum's avatar Guido van Rossum

Patch by Tim Peters:

Introduce a new builtin exception, UnboundLocalError, raised when ceval.c
tries to retrieve or delete a local name that isn't bound to a value.
Currently raises NameError, which makes this behavior a FAQ since the same
error is raised for "missing" global names too:  when the user has a global
of the same name as the unbound local, NameError makes no sense to them.
Even in the absence of shadowing, knowing whether a bogus name is local or
global is a real aid to quick understanding.

Example:

D:\src\PCbuild>type local.py
x = 42

def f():
    print x
    x = 13
    return x

f()

D:\src\PCbuild>python local.py
Traceback (innermost last):
  File "local.py", line 8, in ?
    f()
  File "local.py", line 4, in f
    print x
UnboundLocalError: x

D:\src\PCbuild>

Note that UnboundLocalError is a subclass of NameError, for compatibility
with existing class-exception code that may be trying to catch this as a
NameError.  Unfortunately, I see no way to make this wholly compatible
with -X (see comments in bltinmodule.c):  under -X, [UnboundLocalError
is an alias for NameError --GvR].

[The ceval.c patch differs slightly from the second version that Tim
submitted; I decided not to raise UnboundLocalError for DELETE_NAME,
only for DELETE_LOCAL.  DELETE_NAME is only generated at the module
level, and since at that level a NameError is raised for referencing
an undefined name, it should also be raised for deleting one.]
üst 43128905
......@@ -78,6 +78,7 @@ extern DL_IMPORT(PyObject *) PyExc_SyntaxError;
extern DL_IMPORT(PyObject *) PyExc_SystemError;
extern DL_IMPORT(PyObject *) PyExc_SystemExit;
extern DL_IMPORT(PyObject *) PyExc_TypeError;
extern DL_IMPORT(PyObject *) PyExc_UnboundLocalError;
extern DL_IMPORT(PyObject *) PyExc_ValueError;
extern DL_IMPORT(PyObject *) PyExc_ZeroDivisionError;
......
......@@ -40,6 +40,8 @@ Exception(*)
| +-- NotImplementedError(*)
|
+-- NameError
| |
| +-- UnboundLocalError(*)
+-- AttributeError
+-- SyntaxError
+-- TypeError
......@@ -208,7 +210,11 @@ class AttributeError(StandardError):
pass
class NameError(StandardError):
"""Name not found locally or globally."""
"""Name not found globally."""
pass
class UnboundLocalError(NameError):
"""Local name referenced but not bound to a value."""
pass
class MemoryError(StandardError):
......
......@@ -2232,6 +2232,7 @@ PyObject *PyExc_NotImplementedError;
PyObject *PyExc_SyntaxError;
PyObject *PyExc_SystemError;
PyObject *PyExc_SystemExit;
PyObject *PyExc_UnboundLocalError;
PyObject *PyExc_TypeError;
PyObject *PyExc_ValueError;
PyObject *PyExc_ZeroDivisionError;
......@@ -2261,6 +2262,11 @@ bltin_exc[] = {
{"KeyError", &PyExc_KeyError, 1},
{"KeyboardInterrupt", &PyExc_KeyboardInterrupt, 1},
{"MemoryError", &PyExc_MemoryError, 1},
/* Note: NameError is not a leaf in exceptions.py, but unlike
the other non-leafs NameError is meant to be raised directly
at times -- the leaf_exc member really seems to mean something
like "this is an abstract base class" when false.
*/
{"NameError", &PyExc_NameError, 1},
{"OverflowError", &PyExc_OverflowError, 1},
{"RuntimeError", &PyExc_RuntimeError, 1},
......@@ -2268,6 +2274,7 @@ bltin_exc[] = {
{"SyntaxError", &PyExc_SyntaxError, 1},
{"SystemError", &PyExc_SystemError, 1},
{"SystemExit", &PyExc_SystemExit, 1},
{"UnboundLocalError", &PyExc_UnboundLocalError, 1},
{"TypeError", &PyExc_TypeError, 1},
{"ValueError", &PyExc_ValueError, 1},
{"ZeroDivisionError", &PyExc_ZeroDivisionError, 1},
......@@ -2420,6 +2427,14 @@ initerrors(dict)
PyTuple_SET_ITEM(PyExc_EnvironmentError, 1, PyExc_OSError);
PyDict_SetItemString(dict, "EnvironmentError", PyExc_EnvironmentError);
/* Make UnboundLocalError an alias for NameError */
Py_INCREF(PyExc_NameError);
Py_DECREF(PyExc_UnboundLocalError);
PyExc_UnboundLocalError = PyExc_NameError;
if (PyDict_SetItemString(dict, "UnboundLocalError",
PyExc_NameError) != 0)
Py_FatalError("Cannot create string-based exceptions");
/* missing from the StandardError tuple: Exception, StandardError,
* and SystemExit
*/
......
......@@ -1320,7 +1320,7 @@ eval_code2(co, globals, locals,
case LOAD_FAST:
x = GETLOCAL(oparg);
if (x == NULL) {
PyErr_SetObject(PyExc_NameError,
PyErr_SetObject(PyExc_UnboundLocalError,
PyTuple_GetItem(co->co_varnames,
oparg));
break;
......@@ -1338,7 +1338,7 @@ eval_code2(co, globals, locals,
case DELETE_FAST:
x = GETLOCAL(oparg);
if (x == NULL) {
PyErr_SetObject(PyExc_NameError,
PyErr_SetObject(PyExc_UnboundLocalError,
PyTuple_GetItem(co->co_varnames,
oparg));
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment