Printing without parentheses varying error message using Python 3

后端 未结 4 1138
被撕碎了的回忆
被撕碎了的回忆 2021-02-05 02:22

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):
  ...
           


        
4条回答
  •  孤独总比滥情好
    2021-02-05 03:02

    The special exception message for print used as statement instead of as function is actually implemented as a special case.

    Roughly speaking when a SyntaxError is created it calls a special function that checks for a print statement based on the line the exception refers to.

    However, the first test in this function (the one responsible for the "Missing parenthesis" error message) is if there is any opening parenthesis in the line. I copied the source code for that function (CPython 3.6.4) and I marked the relevant lines with "arrows":

    static int
    _report_missing_parentheses(PySyntaxErrorObject *self)
    {
        Py_UCS4 left_paren = 40;
        Py_ssize_t left_paren_index;
        Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text);
        int legacy_check_result = 0;
    
        /* Skip entirely if there is an opening parenthesis <---------------------------- */
        left_paren_index = PyUnicode_FindChar(self->text, left_paren,
                                              0, text_len, 1);
        if (left_paren_index < -1) {
            return -1;
        }
        if (left_paren_index != -1) {
            /* Use default error message for any line with an opening parenthesis <------------ */
            return 0;
        }
        /* Handle the simple statement case */
        legacy_check_result = _check_for_legacy_statements(self, 0);
        if (legacy_check_result < 0) {
            return -1;
    
        }
        if (legacy_check_result == 0) {
            /* Handle the one-line complex statement case */
            Py_UCS4 colon = 58;
            Py_ssize_t colon_index;
            colon_index = PyUnicode_FindChar(self->text, colon,
                                             0, text_len, 1);
            if (colon_index < -1) {
                return -1;
            }
            if (colon_index >= 0 && colon_index < text_len) {
                /* Check again, starting from just after the colon */
                if (_check_for_legacy_statements(self, colon_index+1) < 0) {
                    return -1;
                }
            }
        }
        return 0;
    }
    

    That means it won't trigger the "Missing parenthesis" message if there is any opening parenthesis in the line. That leads to the general SyntaxError message even if the opening parenthesis is in a comment:

    print 10  # what(
        print 10  # what(
               ^
    SyntaxError: invalid syntax
    

    Note that the cursor position for two names/variables separated by a white space is always the end of the second name:

    >>> 10 100
        10 100
             ^
    SyntaxError: invalid syntax
    
    >>> name1 name2
        name1 name2
                  ^
    SyntaxError: invalid syntax
    
    >>> name1 name2([1, 2])
        name1 name2([1, 2])
                  ^
    SyntaxError: invalid syntax
    

    So it is no wonder the cursor points to the x of max, because it's the last character in the second name. Everything that follows the second name (like ., (, [, ...) is ignored, because Python already found a SyntaxError, and it doesn't need to go further, because nothing could make it valid syntax.

提交回复
热议问题