diff Python/bltinmodule.c @ 11030:3be935be3781 legacy-trunk

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.]
author Guido van Rossum <guido@python.org>
date Tue, 22 Jun 1999 14:47:32 +0000
parents e9442734bc49
children 41a46978a444
line wrap: on
line diff
--- a/Python/bltinmodule.c	Mon Jun 21 22:36:53 1999 +0000
+++ b/Python/bltinmodule.c	Tue Jun 22 14:47:32 1999 +0000
@@ -2232,6 +2232,7 @@
 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 @@
 	{"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 @@
 	{"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 @@
 	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
 	 */