在Python 3.4中,当我try 在一个简单名称上使用不带括号的print时,我得到:

>>> 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

(请注意,在这种情况下,光标指向第一个点之前的字符.)

消息是不同的(而且有点误导,因为标记低于max函数).

为什么Python不能更早地检测到问题?

注意:这个问题的灵感来源于围绕这个问题的困惑:100,由于错误消息的误导,一些Python专家错过了真正的问题.

推荐答案

看看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个语法错误.这一直都是一个语法错误,但关于括号的实际小片段在之后被捕捉,只是为了给出一个额外的提示.

Python-3.x相关问答推荐

如何在M x N数组的行中找到所有值的组合

使用 iloc 或 loc 对多列进行过滤

我无法直接在 VSCode 中运行该程序,但可以使用 VScode 中的终端运行它

如何使用 Selenium Python 连续单击一个按钮直到另一个元素出现?

如何在 histplot 中标记核密度估计

pytorch 中 mps 设备的 manual_seed

matplotlib.pyplot 多边形,具有相同的纵横比和紧凑的布局

使用 selenium 加速网页抓取

Python:获取未绑定的类方法

python tkInter 浏览文件夹按钮

python3源的类图查看器应用程序

Seaborn 热图 colored颜色 条标签作为百分比

'~'(波浪号)运算符在 Python 中的应用

如何通过命令行将数组传递给python

如何在 Selenium 和 Python 中使用类型查找元素

如何在 jupyter notebook 5 中逐行分析 python 3.5 代码

使用 urllib3 忽略证书验证

SQLAlchemy:如果不存在则创建模式

如何强制 Sphinx 使用 Python 3.x 解释器

python中的绝对导入是什么?