看看source code for exceptions.c
,就在_set_legacy_print_statement_msg
的正上方,有一条很好的街区 comments :
/* To help with migration from Python 2, SyntaxError.__init__ applies some
* heuristics to try to report a more meaningful exception when print and
* exec are used like statements.
*
* The heuristics are currently expected to detect the following cases:
* - top level statement
* - statement in a nested suite
* - trailing section of a one line complex statement
*
* They're currently known not to trigger:
* - after a semi-colon
*
* The error message can be a bit odd in cases where the "arguments" are
* completely illegal syntactically, but that isn't worth the hassle of
* fixing.
*
* We also can't do anything about cases that are legal Python 3 syntax
* but mean something entirely different from what they did in Python 2
* (omitting the arguments entirely, printing items preceded by a unary plus
* or minus, using the stream redirection syntax).
*/
这里有一些有趣的信息.此外,在同一文件中的SyntaxError_init
方法中,我们可以看到
/*
* Issue #21669: Custom error for 'print' & 'exec' as statements
*
* Only applies to SyntaxError instances, not to subclasses such
* as TabError or IndentationError (see issue #31161)
*/
if ((PyObject*)Py_TYPE(self) == PyExc_SyntaxError &&
self->text && PyUnicode_Check(self->text) &&
_report_missing_parentheses(self) < 0) {
return -1;
}
还要注意的是,上面提到的issue #21669 on the python bugtracker篇文章中,作者和Guido就如何实现这一点进行了一些讨论.所以我们跟着兔子(也就是_report_missing_parentheses
)走,它在文件的最底部,看到...
legacy_check_result = _check_for_legacy_statements(self, 0);
然而,也有一些情况下,这是绕过和正常的SyntaxError
信息打印,请参阅MSeifert's answer了解更多信息.如果我们将一个函数增加到_check_for_legacy_statements
,我们将看到actual check用于传统打印语句.
/* Check for legacy print statements */
if (print_prefix == NULL) {
print_prefix = PyUnicode_InternFromString("print ");
if (print_prefix == NULL) {
return -1;
}
}
if (PyUnicode_Tailmatch(self->text, print_prefix,
start, text_len, -1)) {
return _set_legacy_print_statement_msg(self, start);
}
所以,为了回答这个问题:"为什么Python不能更早地检测到这个问题?",我想说,括号的问题不是检测到什么;它实际上被解析为after个语法错误.这一直都是一个语法错误,但关于括号的实际小片段在之后被捕捉,只是为了给出一个额外的提示.