使用 Python 3 打印不带括号的不同错误消息 [英] Printing without parentheses varying error message using Python 3

查看:46
本文介绍了使用 Python 3 打印不带括号的不同错误消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

<预><代码>>>>打印最大值回溯(最近一次调用最后一次):...文件<交互式输入>",第 1 行打印最大值^语法错误:调用打印"时缺少括号

好的,现在我明白了,我只是忘了移植我的 Python 2 代码.

但是现在当我尝试打印函数的结果时:

<预><代码>>>>打印最大值([1,2])回溯(最近一次调用最后一次):...打印最大值([1,2])^语法错误:无效语法

或者:

print max.__call__(23)^语法错误:无效语法

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

消息是不同的(并且有点误导,因为标记位于 max 函数下方).

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

注意:这个问题的灵感来自围绕这个问题的困惑:熊猫阅读.csv 语法错误,其中一些 Python 专家由于误导性错误消息而错过了真正的问题.

解决方案

exceptions.c 的源代码,在 _set_legacy_print_statement_msg 的正上方有一个不错的块注释:

/* 为了帮助从 Python 2 迁移,SyntaxError.__init__ 应用了一些* 尝试在打印和打印时报告更有意义的异常的启发式方法* exec 像语句一样使用.** 目前预计启发式方法可检测以下情况:* - 顶级语句* - 嵌套套件中的语句* - 单行复杂语句的尾随部分** 目前已知它们不会触发:* - 在分号之后** 在参数"是的情况下,错误消息可能有点奇怪* 在语法上完全非法,但这不值得麻烦* 固定.** 对于合法的 Python 3 语法,我们也无能为力* 但意味着与他们在 Python 2 中所做的完全不同的事情*(完全省略参数,打印以一元加号开头的项目* 或减号,使用流重定向语法).*/

所以有一些有趣的信息.另外,在同一个文件中的SyntaxError_init方法中,我们可以看到

/** 问题 #21669:打印"& 的自定义错误'exec' 作为语句** 仅适用于 SyntaxError 实例,不适用于子类,例如* 作为 TabError 或 IndentationError(参见问题 #31161)*/if ((PyObject*)Py_TYPE(self) == PyExc_SyntaxError &&自我>文本&&PyUnicode_Check(self->text) &&_report_missing_parentheses(self) <0) {返回-1;}

另请注意,以上参考了问题#21669 on the python bugtracker,作者和Guido 关于如何解决这个问题.因此,我们跟随位于文件最底部的兔子(即 _report_missing_parentheses),然后查看...

legacy_check_result = _check_for_legacy_statements(self, 0);

但是,在某些情况下会绕过此操作并打印正常的 SyntaxError 消息,请参阅 MSeifert 的回答了解更多.如果我们将一个函数提升到 _check_for_legacy_statements,我们最终会看到遗留打印语句的实际检查.

/* 检查遗留打印语句 */如果(打印前缀== NULL){print_prefix = PyUnicode_InternFromString("打印");如果(打印前缀== NULL){返回-1;}}if (PyUnicode_Tailmatch(self->text, print_prefix,开始,text_len,-1)) {返回 _set_legacy_print_statement_msg(self, start);}

所以,要回答这个问题:为什么 Python 不能更早地检测到问题?",我会说括号的问题不是检测到的问题;它实际上是在语法错误之后解析的.这一直是一个语法错误,但后来捕获了有关括号的实际小部分只是为了提供额外的提示.

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'

Ok, now I get it, I just forgot to port my Python 2 code.

But now when I try to print the result of a function:

>>> print max([1,2])
Traceback (most recent call last):
    ...
    print max([1,2])
            ^
SyntaxError: invalid syntax

Or:

print max.__call__(23)
        ^
SyntaxError: invalid syntax

(Note that the cursor is pointing to the character before the first dot in that case.)

The message is different (and slightly misleading, since the marker is below the max function).

Why isn't Python able to detect the problem earlier?

Note: This question was inspired by the confusion around this question: Pandas read.csv syntax error, where a few Python experts missed the real issue because of the misleading error message.

解决方案

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);
}

So, to answer the question: "Why isn't Python able to detect the problem earlier?", I would say the problem with parentheses isn't what is detected; it is actually parsed after the syntax error. It's a syntax error the whole time, but the actual minor piece about parentheses is caught afterwards just to give an additional hint.

这篇关于使用 Python 3 打印不带括号的不同错误消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆