When I try to use print
without parentheses on a simple name in Python 3.4 I get:
>>> print max
Traceback (most recent call last):
...
File "<interactive input>", line 1
print max
^
SyntaxError: Missing parentheses in call to 'print'
好的,现在我明白了,我只是忘了移植我的Python 2代码。
但是现在当我尝试打印函数的结果时:
>>> print max([1,2])
Traceback (most recent call last):
...
print max([1,2])
^
SyntaxError: invalid syntax
要么:
print max.__call__(23)
^
SyntaxError: invalid syntax
(请注意,在这种情况下,光标指向第一个点之前的字符。)
The message is different (and slightly misleading, since the marker is below the max
function).
为什么Python无法更早地发现问题?
注意:这个问题是由以下问题引起的:Pandas read.csv语法错误,其中一些Python专家由于误导性错误消息而错过了真正的问题。
最佳答案
Looking at the source code for exceptions.c
, right above _set_legacy_print_statement_msg
there's this nice block comment:
/* 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).
*/
So there's some interesting info. In addition, in the SyntaxError_init
method in the same file, we can see
/*
* 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;
}
Note also that the above references issue #21669 on the python bugtracker with some discussion between the author and Guido about how to go about this. So we follow the rabbit (that is, _report_missing_parentheses
) which is at the very bottom of the file, and see...
legacy_check_result = _check_for_legacy_statements(self, 0);
However, there are some cases where this is bypassed and the normal SyntaxError
message is printed, see MSeifert's answer for more about that. If we go one function up to _check_for_legacy_statements
we finally see the actual check for legacy print statements.
/* 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无法更早地检测到该问题?”,我会说括号中的问题不是检测到的;它实际上是在语法错误之后进行解析的。一直以来这都是一个语法错误,但是后来捕获了关于括号的实际小片段,只是为了给出一个额外的提示。