Python 中的无效语法:SyntaxError 的常见原因 您所在的位置:网站首页 对象可能包含无效语法或不支持的字符吗 Python 中的无效语法:SyntaxError 的常见原因

Python 中的无效语法:SyntaxError 的常见原因

2024-07-18 03:28| 来源: 网络整理| 查看: 265

Python 中的无效语法:SyntaxError 的常见原因

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

学完本教程后,您将能够:

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

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

当您第一次学习 Python 时,遇到 SyntaxError 可能会令人沮丧。 Python 将尝试帮助您确定代码中无效语法的位置,但它提供的回溯可能有点令人困惑。有时,它指向的代码完全没问题。

注意:如果您的代码语法正确,那么您可能会引发除SyntaxError之外的其他异常。要了解有关 Python 的其他异常以及如何处理它们的更多信息,请查看 Python 异常:简介。

你不能像其他异常一样处理 Python 中的无效语法。即使您尝试使用无效语法将 try 和 except 块包装在代码周围,您仍然会看到解释器引发 SyntaxError。

SyntaxError 异常和回溯

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

# theofficefacts.py ages = { 'pam': 24, 'jim': 24 'michael': 43 } print(f'Michael is {ages["michael"]} years old.')

您可以在第 4 行的字典文字中看到无效语法。第二个条目 'jim' 缺少逗号。如果您尝试按原样运行此代码,那么您将得到以下回溯:

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

请注意,回溯消息将错误定位在第 5 行,而不是第 4 行。Python 解释器试图指出无效语法的位置。然而,它只能真正指出它首先注意到问题的地方。当您收到 SyntaxError 回溯并且回溯指向的代码看起来正常时,您将需要开始向后移动代码,直到确定问题所在。

在上面的示例中,省略逗号没有问题,具体取决于逗号后面的内容。例如,第 5 行中 'michael' 后面缺少逗号是没有问题的。但是一旦解释器遇到一些没有意义的东西,它只能将你指向它发现的第一个东西它无法理解。

注意:本教程假设您了解 Python 回溯的基础知识。要了解有关 Python 回溯以及如何读取它们的更多信息,请查看了解 Python 回溯和充分利用 Python 回溯。

SyntaxError 回溯中有一些元素可以帮助您确定代码中无效语法的位置:

遇到无效语法的文件名遇到问题的行号和重现的代码行复制代码下方的行上的脱字号 (^),它显示代码中存在问题的点异常类型SyntaxError之后出现的错误消息,可以提供帮助您确定问题的信息

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

您可能会看到 Python 引发另外两个异常。这些与 SyntaxError 等效,但具有不同的名称:

IndentationErrorTabError

这些异常都继承自 SyntaxError 类,但它们是涉及缩进的特殊情况。当代码的缩进级别不匹配时,会引发 IndentationError。当您的代码在同一文件中同时使用制表符和空格时,会引发 TabError。您将在后面的部分中仔细研究这些异常。

常见语法问题

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

滥用赋值运算符 (=)

在 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 关键字赋值时,您也可能会遇到此问题,您将在下一节中介绍这一问题。

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

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

错误使用关键字的常见方式有以下三种:

关键字拼写错误缺少关键字滥用关键字

如果您在 Python 代码中拼错关键字,那么您将收到SyntaxError。例如,如果关键字 for 拼写错误,会发生以下情况:

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

该消息显示为 SyntaxError: invalid syntax,但这并没有多大帮助。回溯指向 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'在循环外”和“'Continue'在循环中不正确”可帮助您准确地弄清楚该怎么做。如果此代码位于文件中,那么 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,它在 Python 2 与 Python 3 中有所不同:

Python 2

关键词

Python 3

内置功能

print 是 Python 2 中的关键字,因此您无法为其赋值。然而,在 Python 3 中,它是一个可以赋值的内置函数。

您可以运行以下代码来查看您正在运行的任何版本的 Python 中的关键字列表:

import keyword print(keyword.kwlist)

keyword 还提供了有用的 keyword.iskeyword()。如果您只需要一种快速方法来检查 pass 变量,那么您可以使用以下单行代码:

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

此代码将快速告诉您您尝试使用的标识符是否是关键字。

缺少圆括号、方括号和引号

通常,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

这次,回溯中的插入符号直接指向问题代码。 SyntaxError 消息“扫描字符串文字时 EOL” 更加具体,有助于确定问题。这意味着 Python 解释器在打开的字符串关闭之前就到达了行尾 (EOL)。要解决此问题,请使用与开始字符串相匹配的引号来结束字符串。在本例中,这将是双引号 (")。

f 字符串内的语句中缺少引号也会导致 Python 中的语法无效:

# theofficefacts.py ages = { 'pam': 24, 'jim': 24, 'michael': 43 } print(f'Michael is {ages["michael]} years old.')

在这里,打印的 f 字符串中对ages 字典的引用缺少关键引用的右双引号。回溯结果如下:

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

Python 识别问题并告诉您问题存在于 f 字符串内。消息“未终止的字符串”也表明了问题所在。在这种情况下,插入符号仅指向 f 字符串的开头。

这可能不如插入符号指向 f 字符串的问题区域那么有用,但它确实缩小了您需要查看的范围。 f 字符串内部有一个未终止的字符串。你只需要找出在哪里。要解决此问题,请确保所有内部 f 字符串引号和括号都存在。

缺少圆括号和方括号的情况基本相同。例如,如果您在列表中遗漏了右方括号,那么 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 使用空格对事物进行逻辑分组,并且由于没有逗号或括号将 3 与 print(foo()) 分开,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 很难识别缺少的圆括号和中括号。有时,您唯一能做的就是从插入符号开始并向后移动,直到您能够确定缺少或错误的内容。

字典语法错误

您之前看到,如果在字典元素中省略逗号,可能会出现 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() 来定义字典。

使用错误的缩进

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

IndentationErrorTabError

其他编程语言使用大括号来表示代码块,而 Python 使用空格。这意味着 Python 希望代码中的空白表现得可预测。如果代码块中的一行的空格数错误,它将引发 IndentationError:

# indentation.py def foo(): for i in range(10): print(i) print('done') foo()

这可能很难看出来,但第 5 行只缩进了 2 个空格。它应该与 for 循环语句一致,多了 4 个空格。值得庆幸的是,Python 可以轻松发现这一点,并很快告诉您问题所在。

不过,这里也存在一些含糊之处。 print('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,只要有一行包含制表符或空格作为缩进,您就会看到它,而文件的其余部分包含另一个。这可能会被隐藏起来,直到 Python 向您指出为止!

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

# indentation.py def foo(): for i in range(10): print(i) print('done') 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 行在所有三个示例中都使用一个制表符。选项卡的宽度根据选项卡宽度设置而变化:

如果制表符宽度为 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'。

定义和调用函数

当您定义或调用函数时,您可能会在 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

在这里,错误消息再次非常有助于告诉您线路到底出了什么问题。

更改Python版本

有时,在一个版本的 Python 中运行得非常好的代码在新版本中会崩溃。这是由于语言语法的官方更改所致。最著名的例子是 print 语句,它从 Python 2 中的关键字变成了 Python 3 中的内置函数:

>>> # 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 字符串语法,在 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 字符串语法一无所知,只会提供通用的“无效语法”消息。在本例中,问题在于代码看起来完全正常,但它是使用旧版本的 Python 运行的。如有疑问,请仔细检查您正在运行的 Python 版本!

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

海象运算符(赋值表达式)用于调试的 F 字符串语法仅位置参数

如果您想尝试其中一些新功能,那么您需要确保您在 Python 3.8 环境中工作。否则,您将收到SyntaxError。

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

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

这个 TypeError 意味着你不能像函数一样调用元组,而 Python 解释器认为你正在这样做。

在 Python 3.8 中,此代码仍然会引发 TypeError,但现在您还会看到一个 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 实验室设备网 版权所有