考虑以下verysimple.py
:
if '__main__' == __name__:
prnt('Line1')
现在,如果我用> python verysimple.py
执行它,我当然会受到以下问题的欢迎:
Traceback (most recent call last):
File "verysimple.py", line 2, in <module>
prnt('Line1')
NameError: name 'prnt' is not defined`
我想知道python-c-api Python中的哪些地方正在提取回溯信息(特别是错误的命令)。
我已经尝试在PyEval_FrameEx
内找到自己的方式,但无法理解......
答案 0 :(得分:1)
你走在正确的轨道上。解析代码树时,它只会多次运行PyEval_FrameEx
。
最后,它将调用format_exc_check_arg()
来格式化错误,对于我来说,这发生在Python版本3.3.2源代码的ceval.c
的第2100行。
format_exc_check_arg()
推断出令人反感的“对象”(prnt
),并在PyErr_Format
中调用errors.c
来正确格式化异常字符串(异常类型及其对应的字符串,{{1} },已从此行2100传递给NAME_ERROR_MSG
。
我只使用此代码进行测试:
format_exc_check_arg()
然后通过我所拥有的Python的debug build运行它。
prnt('Line1')
中的周围代码是
PyEval_FrameEx
请注意,其上方的两行 TARGET(LOAD_NAME)
w = GETITEM(names, oparg);
if ((v = f->f_locals) == NULL) {
PyErr_Format(PyExc_SystemError,
"no locals when loading %R", w);
why = WHY_EXCEPTION;
break;
}
if (PyDict_CheckExact(v)) {
x = PyDict_GetItem(v, w);
Py_XINCREF(x);
}
else {
x = PyObject_GetItem(v, w);
if (x == NULL && PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(
PyExc_KeyError))
break;
PyErr_Clear();
}
}
if (x == NULL) {
x = PyDict_GetItem(f->f_globals, w);
Py_XINCREF(x);
if (x == NULL) {
if (PyDict_CheckExact(f->f_builtins)) {
x = PyDict_GetItem(f->f_builtins, w);
if (x == NULL) {
// below is the line where the PyExc_NameError will be properly formatted.
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, w);
break;
}
Py_INCREF(x);
}
else {
x = PyObject_GetItem(f->f_builtins, w);
if (x == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
format_exc_check_arg(
PyExc_NameError,
NAME_ERROR_MSG, w);
break;
}
}
}
}
PUSH(x);
DISPATCH();
将是试图在内置语句中找到PyDict_GetItem(...)
的行。函数(我从prnt
推导出f->builtins
到w
,w
本身来自上面代码中的第二个语句。
由于该字典查找失败,x == NULL
和NameError
已设置并格式化。
希望这会对你有所帮助。