]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Patch by Tim Peters:
authorGuido van Rossum <guido@python.org>
Tue, 22 Jun 1999 14:47:32 +0000 (14:47 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 22 Jun 1999 14:47:32 +0000 (14:47 +0000)
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.]

Include/pyerrors.h
Lib/exceptions.py
Python/bltinmodule.c
Python/ceval.c

index 8a8111ab8564dabd30641f34d5ae4427c24370f3..becaabd296ab13e460c95260283caada791f8997 100644 (file)
@@ -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;
 
index e943f7b18830a665a2893ed6899217127bc3f2fb..af752d915e41c0536254fd6c4350ba8dc6ce6823 100644 (file)
@@ -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):
index 3ddf88593ca27372da494d45b5c0cb2e58d5362f..4e20eda4a597b87a4728069a0a21839272585a20 100644 (file)
@@ -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
         */
index 621839790fb6364032a70486ff9bc56a85a292c2..1c51ccf1356478f3ac49db7763c553f364b7470c 100644 (file)
@@ -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;