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