你一定遇到过Python中的无效语法:SyntaxError 您所在的位置:网站首页 java缺少标识符什么意思 你一定遇到过Python中的无效语法:SyntaxError

你一定遇到过Python中的无效语法:SyntaxError

2024-04-06 02:02| 来源: 网络整理| 查看: 265

Python以其简单的语法而闻名。然而,当您第一次学习Python时,或者当您具有另一种编程语言的坚实背景时,您可能会遇到一些Python不允许的事情。如果您在尝试运行Python代码时收到过SyntaxError错误,那么本指南可以帮助您。在本教程中,您将看到Python中常见的无效语法示例,并学习如何解决这个问题。

在本教程结束时,您将能够:

识别Python中的无效语法理解SyntaxError回溯解析无效语法或完全阻止它

Python中的无效语法

当您运行Python代码时,解释器将首先解析它,将其转换成Python字节码,然后执行。解释器将在程序执行的第一阶段(也称为解析阶段)中发现Python中的任何无效语法。如果解释器不能成功地解析您的Python代码,那么这意味着您在代码的某个地方使用了无效的语法。解释器将尝试向您显示错误发生的位置。

当您第一次学习Python时,得到一个SyntaxError可能会令人沮丧。Python将尝试帮助您确定无效语法在代码中的位置,但是它提供的回溯可能会让您感到有些困惑。有时,它所指向的代码是完全正确的。

您不能像处理其他异常一样处理Python中的无效语法。即使您尝试将try和except块封装到带有无效语法的代码中,您仍然会看到解释器抛出一个SyntaxError。

SyntaxError异常和回溯

当解释器在Python代码中遇到无效语法时,它将抛出一个SyntaxError异常,并提供一个带有一些有用信息的回溯,以帮助您调试错误。下面是一些Python中包含无效语法的代码:

1 # theofficefacts.py 2 ages = { 3 'pam': 24, 4 'jim': 24 5 'michael': 43 6 } 7 print(f'Michael is {ages["michael"]} years old.')

您可以在第4行字典的文字中看到无效的语法。第二个词条“jim”漏掉了一个逗号。如果你试着按原样运行这段代码,你会得到以下回溯结果:

$ python theofficefacts.py File "theofficefacts.py", line 5 'michael': 43 ^ SyntaxError: invalid syntax

注意,traceback消息定位的错误在第5行,而不是第4行。Python解释器试图指出无效语法的位置。然而,它只能指出它最初注意到的问题。当您获得一个SyntaxError traceback,并且traceback所指向的代码看起来很好,那么您将希望开始向后移动代码,直到您能够确定哪里出了问题。

在上面的例子中,根据后面的内容,省略逗号是没有问题的。例如,第5行“michael”后面缺少逗号是没有问题的。但是一旦解释器遇到不理解的东西,它只能指出它发现的第一件不理解的事情。

回溯是一个堆栈跟踪,从异常处理程序的点一直到调用链中的异常引发点。您还可以从调用的角度(并且没有错误的上下文)向上使用当前调用堆栈,这对于查找函数所遵循的路径非常有用。

有几个元素的SyntaxError回溯,可以帮助您确定无效的语法在您的代码:

遇到无效语法的文件名遇到问题的行号和代码的复写行在复制代码下面的行中有一个插入符号(^),它向您显示代码中有问题的那一点异常类型SyntaxError之后的错误消息,可以提供帮助您确定问题的信息

在上面的例子中,给出的文件名是theofficefacts。行号为5,插入符号指向字典键michael的结束引用。SyntaxError回溯可能不会指向真正的问题,但它将指向解释器无法理解语法的第一个地方。

您可能会看到Python引发另外两个异常。它们等价于SyntaxError,但有不同的名称:

IndentationErrorTabError

这些异常都继承自SyntaxError类,但它们是涉及缩进的特殊情况。当代码的缩进级别不匹配时,将引发IndentationError。当代码在同一文件中同时使用制表符和空格时,将引发一个制表符错误。在后面的小节中,您将进一步了解这些异常。

常见的语法问题

当您第一次遇到SyntaxError时,了解为什么会出现问题以及如何修复Python代码中的无效语法是很有帮助的。在下面的小节中,您将看到可能引发SyntaxError的一些更常见的原因,以及如何修复它们。

01

误用赋值运算符(=)

在Python中有几种情况下,您不能对对象进行赋值。一些例子是分配文字和函数调用。在下面的代码块中,您可以看到一些尝试这样做的示例和由此产生的SyntaxError回溯:

>>>

>>> len('hello') = 5 File "", line 1 SyntaxError: can't assign to function call >>> 'foo' = 1 File "", line 1 SyntaxError: can't assign to literal >>> 1 = 'foo' File "", line 1 SyntaxError: can't assign to literal

第一个示例尝试将值5分配给len()调用。在这种情况下,SyntaxError消息非常有用。它告诉你不能给函数调用赋值。

第二个和第三个示例尝试将字符串和整数分配给文字。同样的规则也适用于其他文字值。同样,回溯消息表明,当您试图将一个值赋给一个文字时,问题就会发生。

注意:上面的示例缺少重复的代码行和指向回溯中的问题的插入符号(^)。当您在REPL中尝试从文件中执行这段代码时,您看到的异常和回溯将是不同的。如果这个代码在一个文件中,那么您将得到重复的代码行和指向问题的插入符号,正如您在本教程的其他情况中看到的那样。

很可能你的目的不是给文字或函数调用赋值。例如,如果您不小心省略了额外的等号(=),就会发生这种情况,这会将赋值转换为比较。如下所示,比较是有效的:

>>>

>>> len('hello') == 5 True

大多数情况下,当Python告诉您正在对无法赋值的东西进行赋值时,您首先可能需要检查以确保语句不应该是布尔表达式。当您试图为Python关键字赋值时,也可能遇到这个问题,下一节将讨论这个问题。

02

拼写错误、缺少或误用Python关键字

Python关键字是一组在Python中具有特殊含义的受保护的单词。这些词在代码中不能用作标识符、变量或函数名。它们是语言的一部分,只能在Python允许的上下文中使用。

有三种常见的方式,你可以错误地使用关键字:

拼错的关键字缺少一个关键字滥用关键字

如果您在Python代码中拼错了关键字,那么您将得到一个SyntaxError。例如,如果你把关键字拼错了,会发生以下情况:

>>> fro i in range(10): File "", line 1 fro i in range(10): ^ SyntaxError: invalid syntax

消息将读取SyntaxError:无效语法,但这没有多大帮助。回溯指向Python可以检测到错误的第一个地方。要修复这类错误,请确保所有Python关键字拼写正确。

另一个关于关键字的常见问题是你完全忽略了它们:

>>>

>>> for i range(10): File "", line 1 for i range(10): ^ SyntaxError: invalid syntax

同样,异常消息也不是很有用,但是回溯确实试图为您指出正确的方向。如果从插入符号返回,则可以看到for循环语法中缺少关键字in。

您还可能误用受保护的Python关键字。记住,关键字只允许在特定的情况下使用。如果您不正确地使用它们,那么您的Python代码中就会出现无效的语法。一个常见的例子是在循环外使用continue或break。这在开发过程中很容易发生,当你在实现一些东西的时候,碰巧把逻辑移出了一个循环:

>>> names = ['pam', 'jim', 'michael'] >>> if 'jim' in names: ... print('jim found') ... break ... File "", line 3 SyntaxError: 'break' outside loop >>> if 'jim' in names: ... print('jim found') ... continue ... File "", line 3 SyntaxError: 'continue' not properly in loop

在这里,Python很好地告诉了您到底哪里出了问题。"'break' outside loop"和" continue' not exactly in loop"这两个信息可以帮助你明确地知道该怎么做。如果这段代码在一个文件中,那么Python也会让插入符号指向被误用的关键字。

另一个例子是,如果你尝试给一个变量分配一个Python关键字,或者使用一个关键字来定义一个函数:

>>>

>>> pass = True File "", line 1 pass = True ^ SyntaxError: invalid syntax >>> def pass(): File "", line 1 def pass(): ^ SyntaxError: invalid syntax

当您试图为pass分配一个值时,或者当您试图定义一个名为pass的新函数时,您将得到一个SyntaxError并再次看到“无效语法”消息。

在Python代码中解决这种类型的无效语法可能会稍微困难一些,因为代码从外部看起来没什么问题。如果您的代码看起来不错,但是您仍然会得到一个SyntaxError,那么您可以考虑检查您想要使用的变量名或函数名与您正在使用的Python版本的关键字列表。

受保护的关键字列表随着Python的每个新版本而改变。例如,在Python 3.6中,您可以使用await作为变量名或函数名,但是在Python 3.7中,这个单词已经被添加到关键字列表中。现在,如果您尝试使用await作为变量名或函数名,如果您的代码是Python 3.7或更高版本,那么这将导致SyntaxError。

另一个例子是print,它在python2和python3中有所不同:

Version

print Type

Takes A Value

Python 2

keyword

no

Python 3

built-in function

yes

print是python2中的一个关键字,所以你不能给它赋值。然而,在python3中,它是一个可以赋值的内置函数。

你可以运行以下代码来查看关键字列表,无论你运行的Python版本是什么:

import keyword print(keyword.kwlist)yword.iskey

keyword还提供了有用的keyword.iskeyword()。如果你只是需要一个快速的方法来检查通过变量,那么你可以使用以下一行:

>>> import keyword; keyword.iskeyword('pass') True

这段代码将快速告诉您要使用的标识符是否是关键字。

03

缺少括号、方括号和引号

通常,Python代码中无效语法的原因是缺少或不匹配的右括号、方括号或引号。在嵌套圆括号的很长行或更长的多行块中很难发现这些。你可以通过Python的回溯来发现不匹配或缺失的引用:

>>>

>>> message = 'don't' File "", line 1 message = 'don't' ^ SyntaxError: invalid syntax

这里,回溯指向无效代码,其中在结束单引号后有一个t'。要解决这个问题,您可以进行以下两种更改之一:

用反斜杠转义单引号('don\t')将整个字符串用双引号括起来(“don't”)

另一个常见的错误是忘记关闭字符串。对于双引号和单引号字符串,情况和回溯是相同的:

>>>

>>> message = "This is an unclosed string File "", line 1 message = "This is an unclosed string ^ SyntaxError: EOL while scanning string literal

这一次,traceback中的插入符号指向问题代码。SyntaxError消息“在扫描字符串文字时的EOL”更具体一些,有助于确定问题。这意味着Python解释器在一个开放字符串关闭之前到达该行(EOL)的末尾。要解决这个问题,请使用与开始时匹配的引号关闭字符串。在本例中,将使用双引号(")。

在f-string语句中缺少引号也会导致Python中无效的语法:

1 # theofficefacts.py 2 ages = { 3 'pam': 24, 4 'jim': 24, 5 'michael': 43 6 } 7 print(f'Michael is {ages["michael]} years old.')

这里,打印的f-string中对ages字典的引用缺少关键引用的双引号。得到的回溯结果如下:

$ python theofficefacts.py File "theofficefacts.py", line 7 print(f'Michael is {ages["michael]} years old.') ^ SyntaxError: f-string: unterminated string

Python识别问题并告诉您它存在于f-string中。消息“未终止字符串”也指出了问题所在。本例中的插入符号仅指向f-string的开头。

当插入符号指向f-string的问题区域时,这可能没有那么有用,但是它确实缩小了您需要查找的范围。在那个f字串的某个地方有一个未终止的字符串。你只需要找到在哪里。要修复此问题,请确保所有内部f-string引号和方括号都已存在。

缺少括号和方括号的情况大致相同。例如,如果您从列表中删除了右方括号,那么Python将会发现并指出它。然而,这有一些变化。第一种是把列表中的右括号去掉:

# missing.py def foo(): return [1, 2, 3 print(foo())

当你运行这段代码时,你会被告知调用print()有一个问题:

$ python missing.py File "missing.py", line 5 print(foo()) ^ SyntaxError: invalid syntax

这里发生的是Python认为列表包含三个元素:1、2和3 print(foo())。Python使用空格从逻辑上对事物进行分组,因为从print(foo())中没有逗号或括号分隔3,所以Python将它们集中在一起作为列表的第三个元素。

另一种变化是在列表的最后一个元素后面添加一个逗号,同时仍然去掉右方括号:

# missing.py def foo(): return [1, 2, 3, print(foo())

现在你得到了一个不同的回溯:

$ python missing.py File "missing.py", line 6 ^ SyntaxError: unexpected EOF while parsing

在前面的例子中,3和print(foo())被集中在一起作为一个元素,但是在这里你可以看到一个逗号将两者分开。现在,print(foo())的调用被添加为列表的第四个元素,Python到达了文件的末尾,但没有使用右括号。回溯告诉您,Python已经到达了文件(EOF)的末尾,但是它还在期待其他内容。

在本例中,Python希望有一个右括号(]),但是重复的行和插入符号没有多大帮助。缺少括号和方括号是Python很难识别的。有时,您唯一能做的就是从插入符号开始,然后向后移动,直到您能够识别出缺失或错误的地方。

04

字典语法错误

您在前面已经看到,如果将dictionary元素中的逗号去掉,可能会得到SyntaxError。Python字典的另一种无效语法形式是使用等号(=)来分隔键和值,而不是冒号:

>>>

>>> ages = {'pam'=24} File "", line 1 ages = {'pam'=24} ^ SyntaxError: invalid syntax

同样,这个错误消息不是很有用。但是,重复的行和插入符号非常有用!他们直接指向问题人物。

如果您将Python语法与其他编程语言的语法混淆,那么这种类型的问题很常见。如果将定义字典的行为与dict()调用相混淆,也会看到这种情况。要解决这个问题,可以用冒号替换等号。你也可以切换到使用dict():

>>>

>>> ages = dict(pam=24) >>> ages {'pam': 24}

如果dict()语法更有帮助,那么可以使用它来定义字典。

05

使用错误的缩进

SyntaxError有两个子类专门处理缩进问题:

IndentationErrorTabError

其他编程语言使用花括号表示代码块,而Python使用空格。这意味着Python期望代码中的空白具有可预测性。如果代码块中有一行空格数错误,则会引发IndentationError:

1 # indentation.py 2 def foo(): 3 for i in range(10): 4 print(i) 5 print('done') 6 7 foo()

这可能很难看到,但是第5行只缩进了2个空格。它应该与for循环语句一致,也就是4个空格。幸运的是,Python可以很容易地发现这一点,并很快告诉您问题所在。

不过这里也有一点模糊。打印('done')行是打算在for循环之后还是在for循环块内部?当你运行上述代码,你会看到以下错误:

$ python indentation.py File "indentation.py", line 5 print('done') ^ IndentationError: unindent does not match any outer indentation level

虽然回溯看起来很像SyntaxError回溯,但它实际上是一个IndentationError。错误消息也非常有用。它告诉您行的缩进级别与其他任何缩进级别不匹配。换句话说,print('done')是缩进2个空格的,但是Python找不到任何其他匹配这种缩进级别的代码行。您可以通过确保代码行符合预期的缩进级别来快速修复此问题。

SyntaxError的另一种类型是TabError,只要有一行包含制表符或空格作为缩进,而文件的其余部分包含制表符或空格,就会看到TabError。这可能会隐藏起来,直到Python指出来!

如果制表符的大小与每个缩进级别中的空格数相同,那么看起来所有的行似乎都在同一级别上。然而,如果一行用空格缩进,另一行用制表符缩进,那么Python会指出这是一个问题:

1 # indentation.py 2 def foo(): 3 for i in range(10): 4 print(i) 5 print('done') 6 7 foo()

在这里,第5行是用制表符缩进的,而不是用4个空格。根据您的系统设置,这个代码块在您看来可能是完美的,也可能是完全错误的。

但是,Python会立即注意到这个问题。但在你运行代码,看看Python会告诉你什么是错误的之前,它可能会对你有帮助,看看在不同的标签宽度设置下的代码是什么样子的一个例子:

$ tabs 4 # Sets the shell tab width to 4 spaces $ cat -n indentation.py 1 # indentation.py 2 def foo(): 3 for i in range(10) 4 print(i) 5 print('done') 6 7 foo() $ tabs 8 # Sets the shell tab width to 8 spaces (standard) $ cat -n indentation.py 1 # indentation.py 2 def foo(): 3 for i in range(10) 4 print(i) 5 print('done') 6 7 foo() $ tabs 3 # Sets the shell tab width to 3 spaces $ cat -n indentation.py 1 # indentation.py 2 def foo(): 3 for i in range(10) 4 print(i) 5 print('done') 6 7 foo()

请注意上面三个示例之间的显示差异。大多数代码为每个缩进级别使用4个空格,但是第5行在所有3个示例中都使用单个选项卡。标签宽度的变化,基于标签宽度的设置:

如果制表符宽度为4,那么print语句看起来就像是在for循环之外。控制台将在循环结束时打印“done”。如果制表符宽度是8,这是很多系统的标准,那么print语句看起来就像是在for循环中。控制台会在每个数字之后打印“done”。如果制表符宽度为3,那么print语句看起来就不合适。在本例中,第5行与任何缩进级别不匹配。

当你运行代码,你会得到以下错误和回溯:

$ python indentation.py File "indentation.py", line 5 print('done') ^ TabError: inconsistent use of tabs and spaces in indentation

请注意TabError而不是通常的SyntaxError。Python指出问题所在,并给出有用的错误消息。它清楚地告诉您,在同一个文件中,制表符和空格用于缩进。

解决这个问题的方法是让同一Python代码文件中的所有行都使用制表符或空格,而不是同时使用制表符和空格。对于上面的代码块,修复方法是删除选项卡并用4个空格替换它,这将在For循环完成后打印“done”。

06

定义和调用函数

在定义或调用函数时,可能会遇到Python中无效的语法。例如,如果在函数定义的末尾使用分号而不是冒号,就会看到SyntaxError:

>>>

>>> def fun(); File "", line 1 def fun(); ^ SyntaxError: invalid syntax

这里的回溯非常有用,插入符号直接指向问题字符。您可以通过将分号替换为冒号来清除Python中的这种无效语法。

此外,函数定义和函数调用中的关键字参数的顺序必须正确。关键字参数总是跟在位置参数之后。如果不使用此顺序,将导致SyntaxError:

>>>

>>> def fun(a, b): ... print(a, b) ... >>> fun(a=1, 2) File "", line 1 SyntaxError: positional argument follows keyword argument

这里,同样,错误消息非常有助于准确地告诉您这行代码的错误之处。

07

Python版本问题

有时候,在一个Python版本中工作得很好的代码会在一个新版本中中断。这是由于语言语法的官方变化。这方面最著名的例子是print语句,它从python2中的一个关键字变成了python3中的一个内置函数:

>>>

>>> # Valid Python 2 syntax that fails in Python 3 >>> print 'hello' File "", line 1 print 'hello' ^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello')?

这是SyntaxError提供的错误消息所展示的示例之一!它不仅告诉您在print调用中缺少圆括号,而且还提供了正确的代码来帮助您修复语句。

您可能会遇到的另一个问题是,当您阅读或学习在较新版本的Python中有效的语法,但在您正在编写的版本中无效的语法时。f-string语法就是一个例子,在3.6之前的Python版本中是不存在的:

>>>

>>> # Any version of python before 3.6 including 2.7 >>> w ='world' >>> print(f'hello, {w}') File "", line 1 print(f'hello, {w}') ^ SyntaxError: invalid syntax

在3.6之前的Python版本中,解释器对f-string语法一无所知,只会提供一个通用的“无效语法”消息。在本例中,问题是代码看起来非常好,但是它是在较老版本的Python中运行的。如果有疑问,请再次检查正在运行的Python版本!

Python语法在不断发展,Python 3.8中引入了一些很酷的新特性:

Walrus操作符(赋值表达式)用于调试的F-string语法Positional-only参数

如果您想尝试这些新特性,那么您需要确保您是在Python 3.8环境中工作。否则,您将得到一个SyntaxError。

Python 3.8还提供了新的SyntaxWarning。在语法有效但看起来仍然可疑的情况下,您将看到此警告。例如,如果列表中的两个元组之间缺少逗号。这在3.8之前的Python版本中是有效的语法,但是代码会产生一个类型错误,因为tuple是不可调用的:

>>>

>>> [(1,2)(2,3)] Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object is not callable

这个类型错误意味着您不能像调用函数那样调用元组,这是Python解释器认为您正在做的。

在Python 3.8中,这段代码仍然会引发类型错误,但是现在您还会看到一个SyntaxWarning,它指示如何着手修复问题:

>>>

>>> [(1,2)(2,3)] :1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma? Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object is not callable

新SyntaxWarning附带的有用信息甚至提供了一个提示(“也许您漏掉了一个逗号?”),以便为您指出正确的方向!

结论

在本教程中,您已经看到了SyntaxError回溯所提供的信息。您还看到了Python中许多常见的无效语法示例,以及这些问题的解决方案。这不仅会加快你的工作流程,而且还会使你成为一个更有帮助的代码审查者!

在编写代码时,请尝试使用能够理解Python语法并提供反馈的IDE。如果您将本教程中的许多无效Python代码示例放到一个良好的IDE中,那么它们应该在您执行代码之前突出显示问题行。

在学习Python时获得一个SyntaxError可能会令人沮丧,但是现在您知道了如何理解回溯消息以及在Python中可能遇到的无效语法形式。下一次出现SyntaxError时,您就可以更好地快速修复这个问题了!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有