直接上代码
def foo():
a = 1
def bar():
a = a + 1
return bar()
运行foo(),报错
import dis
def foo():
a = 1
def bar():
a = a + 1
dis.dis(bar)
return bar()
dis打印的内容如下:
很容易明白其意思,,应该是从某个地方加载a,1,执行加法,写回a;
在CPython源码中,搜索“referenced before assignment”
#define NAME_ERROR_MSG \
"name '%.200s' is not defined"
#define GLOBAL_NAME_ERROR_MSG \
"global name '%.200s' is not defined"
#define UNBOUNDLOCAL_ERROR_MSG \
"local variable '%.200s' referenced before assignment"
#define UNBOUNDFREE_ERROR_MSG \
"free variable '%.200s' referenced before assignment" \
" in enclosing scope"
接着搜索UNBOUNDLOCAL_ERROR_MSG
TARGET(LOAD_FAST)
x = GETLOCAL(oparg);
if (x != NULL) {
Py_INCREF(x);
PUSH(x);
FAST_DISPATCH();
}
format_exc_check_arg(PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG,
PyTuple_GetItem(co->co_varnames, oparg));
break;
TARGET(DELETE_FAST)
x = GETLOCAL(oparg);
if (x != NULL) {
SETLOCAL(oparg, NULL);
DISPATCH();
}
format_exc_check_arg(
PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG,
PyTuple_GetItem(co->co_varnames, oparg)
);
break;
static void
format_exc_unbound(PyCodeObject *co, int oparg)
{
PyObject *name;
/* Don't stomp existing exception */
if (PyErr_Occurred())
return;
if (oparg < PyTuple_GET_SIZE(co->co_cellvars)) {
name = PyTuple_GET_ITEM(co->co_cellvars,
oparg);
format_exc_check_arg(
PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG,
name);
} else {
name = PyTuple_GET_ITEM(co->co_freevars, oparg -
PyTuple_GET_SIZE(co->co_cellvars));
format_exc_check_arg(PyExc_NameError,
UNBOUNDFREE_ERROR_MSG, name);
}
}
初步判断是在执行LOAD_FAST时,报出的错误;
如果能够调试就好了,以后试试吧;
顺便提一下,CpythonDoc目录下有这样的解释
>>> x = 10
>>> def foo():
... print(x)
... x += 1
results in an UnboundLocalError:
>>> foo()
Traceback (most recent call last):
...
UnboundLocalError: local variable 'x' referenced before assignment
This is because when you make an assignment to a variable in a scope, that
variable becomes local to that scope and shadows any similarly named variable
in the outer scope. Since the last statement in foo assigns a new value to
``x``, the compiler recognizes it as a local variable. Consequently when the
earlier ``print(x)`` attempts to print the uninitialized local variable and
an error results.