我遇到了 IndentationError(或 TabError)。我该如何修复它?
- 2024-11-15 08:36:00
- admin 原创
- 57
问题描述:
我有一个 Python 脚本:
if True:
if False:
print('foo')
print('bar')
然而,当我尝试运行我的脚本时,Python 引发了一个IndentationError
:
File "script.py", line 4
print('bar')
^
IndentationError: unindent does not match any outer indentation level
我继续调试我的程序,结果总共出现了 4 个错误:
IndentationError: unexpected indent
IndentationError: expected an indented block
TabError: inconsistent use of tabs and spaces in indentation
IndentationError: unindent does not match any outer indentation level
这些错误是什么意思?我做错了什么?我该如何修复我的代码?
这是一个典型问题,旨在涵盖IndentationError
同一地方的一般原因,因为概念问题——知道如何缩进以及为什么/在哪里——是相同的。
对于某些更具体的情况,存在一些已确定的问题,其中概念问题与缩进本身无关:
如何在 Python 中编写一个空的缩进块?在所有内容都按应有的方式排列的情况下,除非在其他地方检测到故意为空的缩进块为错误缩进。
为什么我会从正确缩进的函数(在“try”后面,没有“except”)中收到 IndentationError?对于缺少
except
或finally
块的情况。请注意,最新版本的 Python 会更清楚地报告错误,但旧版本会误导性地将问题检测为后续代码的缩进不正确。复制粘贴到 Python 交互式解释器和缩进中实际上并不是为了获得正确的缩进,而是关于将代码粘贴到 Python 的 REPL 中时会发生什么(因为它每次只期望一个块,手动输入)。然而,这通常会导致报告
IndentationError
。
也可能存在逻辑上不正确的缩进,但不会导致错误。一种常见的情况是附加else:
到for
或while
循环,而不是(按预期)相应的if:
。请参阅Python while 语句中的 Else 子句
请参阅如何修复 Python 缩进,了解更多工具和技术来清理缩进以符合标准(即使它已经“起作用”)。请记住,工具无法自动为您修复错误;它们只能帮助编辑,或应用不影响含义的修饰性更改。
解决方案 1:
为什么缩进很重要?
在 Python 中,缩进用于分隔代码块。这与许多其他使用花括号{}
来分隔块的语言(如 Java、Javascript 和 C)不同。因此,Python 用户必须密切注意何时以及如何缩进代码,因为空格很重要。
当 Python 遇到程序缩进问题时,它会引发名为IndentationError
或 的异常TabError
。也可能因SyntaxError
缩进不正确而导致错误。
一点历史
Python 的创建者Guido van Rossum 在一篇关于 Python 历史的文章{}
中概述了Python 使用缩进而不是更常用的花括号的历史原因:
Python 对缩进的使用直接来自 ABC,但这种想法并非源自 ABC——它已经由 Donald Knuth 推广,并且是一个众所周知的编程风格概念。(occam 编程语言也使用了它。)然而,ABC 的作者确实发明了使用冒号来分隔引导子句和缩进块。在早期不使用冒号的用户测试之后,发现对于刚开始学习编程的初学者来说,缩进的含义不清楚。添加冒号后,情况得到了显著改善:冒号以某种方式吸引人们注意后面的内容,并以正确的方式将前后短语联系在一起。
我如何缩进我的代码?
缩进 Python 代码的基本规则是:基本块中的每个语句必须缩进相同的量。
因此从技术上来说,以下 Python 程序是正确的:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
但是,正如您可能从上面看到的,随意缩进代码会使得阅读和跟踪程序流程变得非常困难。最好保持一致并遵循一种风格。
PEP 8——Python 风格指南——表示:
每个缩进级别使用 4 个空格。
也就是说,每个开始新块的语句以及新块中的每个后续语句都应从当前缩进级别缩进四个空格。以下是按照 PEP8 样式指南缩进的上述程序:
def perm(l):
# Compute the list of all permutations of l
if len(l) <= 1:
return [l]
r = []
for i in range(len(l)):
s = l[:i] + l[i+1:]
p = perm(s)
for x in p:
r.append(l[i:i+1] + x)
return r
我还可以使用标签吗?
Python 意识到有些人仍然更喜欢使用制表符而不是空格,并且旧代码可能使用制表符而不是空格,因此它允许使用制表符作为缩进。PEP8 涉及这个主题:
空格是首选的缩进方法。
制表符应仅用于与已使用制表符缩进的代码保持一致。
但请注意,一个很大的警告是不要同时使用制表符和空格进行缩进。这样做会导致各种奇怪的难以调试的缩进错误。Python将制表符扩展到下一个第 8 列,但如果您的编辑器将制表符大小设置为 4 列,或者您使用空格和制表符,您很容易生成在编辑器中看起来不错的缩进代码,但 Python 将拒绝运行。Python 3 编译器明确拒绝任何包含制表符和空格的模糊混合的程序,通常会引发TabError
。但是,默认情况下,Python 2 中仍然允许混合使用制表符和空格,但强烈建议不要使用此“功能”。使用-t
和-tt
命令行标志分别强制 Python 2 引发警告或(最好)错误。PEP8还讨论了这个主题:
Python 3 不允许混合使用制表符和空格进行缩进。
使用制表符和空格混合缩进的 Python 2 代码应该转换为仅使用空格。
使用 -t 选项调用 Python 2 命令行解释器时,它会发出有关非法混合制表符和空格的代码的警告。使用 -tt 时,这些警告会变成错误。强烈推荐这些选项!
“IndentationError:意外缩进”是什么意思?
问题
当语句不必要地缩进或其缩进与同一块中前几个语句的缩进不一致时,就会发生此错误。例如,以下程序中的第一个语句不必要地缩进:
>>> print('Hello') # this is indented
File "<stdin>", line 1
print('Hello') # this is indented
^
IndentationError: unexpected indent
在此示例中,块can_drive = True
中的行与if
任何前面的语句的缩进不匹配:
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # incorrectly indented
File "<stdin>", line 3
can_drive = True # incorrectly indented
^
IndentationError: unexpected indent
使固定
修复此错误的方法是首先确保有问题的行确实需要缩进。例如,上面的示例使用print
可以简单地通过取消缩进来修复:
>>> print('Hello') # simply unindent the line
Hello
但是,如果您确定该行确实需要缩进,则缩进需要与同一块中前一个语句的缩进相匹配。在上面使用 的第二个示例中,我们可以通过确保带有 的行与主体中前一个语句的缩进级别相同来if
修复错误:can_drive = True
`if`
>>> age = 10
>>> can_drive = None
>>>
>>> if age >= 18:
... print('You can drive')
... can_drive = True # indent this line at the same level.
...
“IndentationError:预期缩进的块”是什么意思?
(这也可能出现SyntaxError: unexpected EOF while parsing
在 Python 3.8 或更低版本中。)
问题
当 Python 看到复合语句的“标头”(例如if <condition>:
或)while <condition>:
但复合语句的主体或块从未定义时,就会发生此错误。例如,在下面的代码中,我们开始了一个if
语句,但从未为该语句定义主体:
>>> if True:
...
File "<stdin>", line 2
^
IndentationError: expected an indented block
在第二个示例中,我们开始编写for
循环,但忘记缩进for
循环体。因此 Python 仍然需要缩进循环体块for
:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name)
File "<stdin>", line 2
print(name)
^
IndentationError: expected an indented block
评论不算作正文:
>>> if True:
... # TODO
...
File "<stdin>", line 3
^
IndentationError: expected an indented block
使固定
修复此错误的方法是简单地包含复合语句的主体。
如上所示,新用户常犯的一个错误是忘记缩进语句主体。如果是这种情况,请确保复合语句主体中要包含的每个语句都与复合语句开头的缩进级别相同。以下是修复后的上述示例:
>>> names = ['sarah', 'lucy', 'michael']
>>> for name in names:
... print(name) # The for loop body is now correctly indented.
...
sarah
lucy
michael
另一种常见情况是,出于某种原因,用户可能不想为复合语句定义实际的主体,或者主体可能被注释掉。在这种情况下,pass
可以使用该语句。摘自文档:
pass 是空操作 — 执行时不会发生任何事情。当语法上需要语句但不需要执行任何代码时,它可用作占位符,例如:
def f(arg): pass # a function that does nothing (yet) class C: pass # a class with no methods (yet)
if
下面是使用关键字修复语句的上述示例pass
:
>>> if True:
... pass # We don't want to define a body.
...
>>>
“IndentationError:unindent 与任何外部缩进级别不匹配”是什么意思?
问题
当您取消缩进某个语句,但现在该语句的缩进级别与任何前一个语句的缩进级别都不匹配时,就会发生此错误。例如,在下面的代码中,我们取消缩进对的第二个调用print
。但是,缩进级别与任何前一个语句的缩进级别都不匹配:
>>> if True:
... if True:
... print('yes')
... print()
File "<stdin>", line 4
print()
^
IndentationError: unindent does not match any outer indentation level
这个错误特别难以发现,因为即使一个空格也会导致代码失败。
使固定
解决方法是确保在取消缩进语句时,缩进级别与前一个语句的缩进级别匹配。再次考虑上述示例。在示例中,我希望第二个 print 调用位于第一个语句主体中。因此,我需要确保该行的缩进级别与第一个语句主体if
中的前一个语句的缩进级别匹配:if
>>> if True:
... if True:
... print('yes')
... print() # indentation level now matches former statement's level.
...
yes
>>>
我仍然收到 IndentationError,但我的程序似乎已正确缩进。我该怎么办?
如果您的程序看起来缩进正确,但仍然出现 ,IndentationError
则很可能是制表符和空格混用。这有时会导致 Python 引发奇怪的错误。请参阅“TabError:缩进中制表符和空格的使用不一致”是什么意思?下的特殊情况小节,以更深入地解释该问题。
“TabError:缩进中制表符和空格的使用不一致”是什么意思?
问题
仅当您尝试将制表符和空格混合用作缩进字符时,才会发生此错误。如上所述,Python 不允许程序包含制表符和空格的混合,TabError
如果发现您这样做,则会引发特定异常。例如,在下面的程序中,制表符和空格的混合用于缩进:
>>> if True:
... if True:
... print()
... print()
... print()
File "<stdin>", line 5
print()
^
TabError: inconsistent use of tabs and spaces in indentation
但这通常无法直观地看出,因为许多编辑器将制表符和空格渲染为相同。请注意,有些编辑器确实提供了使用不同符号渲染制表符和空格的设置,这可能会有所帮助。
对于上面的例子,下面是空白的表示。点是空格,箭头是制表符:
if·True:
····if·True:
→ ····print()
····print()
→ print()
我们可以看到我们确实混合了空格和制表符来进行缩进。
特殊情况
注意:如果在程序中混合使用制表符和空格,Python不会 总是引发TabError
。如果程序缩进明确,Python 将允许混合使用制表符和空格。例如:
>>> if True:
... if True: # tab
... pass # tab, then 4 spaces
...
>>>
有时 Python 会因为制表符和空格的混合而出错,并错误地引发IndentationError
异常,而实际上使用 aTabError
更为合适。另一个示例:
>>> if True:
... print('a') # tab
... print('b') # 4 spaces
File "<stdin>", line 3
print('b') # 4 spaces
^
IndentationError: unindent does not match any outer indentation level
如您所见,以这种方式运行代码可能会产生神秘的错误。尽管程序看起来没有问题,但 Python 在尝试解析用于缩进的制表符和空格时变得混乱,并出错。
这些都是很好的例子,说明了为什么在使用 Python 2 时永远不要混合制表符和空格,并使用-t
和-tt
解释器标志。
使固定
如果您的程序很短,那么最简单、最快捷的解决方法可能是重新缩进程序。确保每个语句每缩进一个级别缩进四个空格(请参阅如何缩进我的代码?)。
但是,如果您已经有一个混合了制表符和空格的大型程序,那么可以使用自动化工具将所有缩进转换为空格。
许多编辑器(例如PyCharm和SublimeText)都有自动将制表符转换为空格的选项。还有一些在线工具(例如Tabs To Spaces或Browserling)可让您快速重新缩进代码。还有一些用 Python 编写的工具。例如, autopep8可以自动重新缩进代码并修复其他缩进错误。
即使是最好的工具有时也无法修复所有缩进错误,您必须手动修复它们。这就是为什么从一开始就正确缩进代码很重要。
SyntaxError
关于相关缩进问题的说明
有时SyntaxError
由于缩进不正确,会引发某些异常。例如,查看以下代码:
if True:
print('x')
print('y') # oops! this statement should be indented!.
else:
print('z')
运行上述代码时,SyntaxError
会引发:
Traceback (most recent call last):
File "python", line 4
else:
^
SyntaxError: invalid syntax
尽管 Python 提出了一个SyntaxError
,但上述代码的真正print('y')
问题在于应该缩进。由于没有缩进,Python 无法意识到前一个if
语句和else
语句是相连的。
修复此类错误的方法是简单地正确地重新缩进代码。要了解如何正确缩进代码,请参阅“如何缩进代码?”部分。
我仍然对 Python 的缩进语法感到困惑。我该怎么办?
如果您仍然遇到困难,请不要灰心。习惯 Python 的空白语法规则可能需要一些时间。以下是一些有用的提示:
找一个编辑器,它会在出现缩进错误时提醒你。上面提到的一些好用的编辑器有PyCharm、SublimeText和Jupyter Notebook。
缩进代码时,大声数一下按了多少次空格键(或 Tab 键)。例如,如果您需要将一行缩进四个空格,则每次按下空格键时,您都会大声说出“一、二、三、四”。这听起来很傻,但它有助于训练您的大脑思考您缩进代码的深度。
如果您有编辑器,请查看它是否有自动将制表符转换为空格的选项。
查看其他人的代码。浏览GitHub或Stack Overflow并查看 Python 代码示例。
只需编写代码。这是进步的唯一最佳方法。你编写的 Python 代码越多,你的进步就越大。
使用的资源
维基百科
Python 3 文档
Guido van Rossum 的《Python 的历史》
PEP 8
解决方案 2:
Sublime Text 3
如果您碰巧在 Sublime Text 3 中编码,这可以帮助您解决缩进问题。
在 Sublime Text 中编辑 Python 文件时:
Sublime,菜单文本→首选项→设置 - 语法特定:
文件Python.sublime-settings
{
"tab_size": 4,
"translate_tabs_to_spaces": true
}
解决方案 3:
快速检查表
不正确的缩进最常见的结果是
IndentationError
,但它也可能导致TabError
( 的子类型IndentationError
)或SyntaxError
(缩进本身是合法的,但它导致其他代码出现语法错误)。对于 Python 代码有效但不符合程序员意图的缩进会导致逻辑错误(代码不会引发异常,但会出错)。强烈建议不要使用制表符进行缩进。在 2.x 中,使用
-tt
命令行参数运行 Python 会导致其引发相同的问题TabError
,这对于查找问题很有用。PEP 8中规定的社区标准是每级缩进使用 4 个空格。
以冒号结尾的语句(例如
if
、、、for
等)while
后面需要
一个缩进块:def
`class`:
if x:
do_y() # <- this must be indented
块不能为空,注释不被视为使块“不为空”。如果什么都不发生,
请使用以下语句:pass
if x:
pass # this statement does nothing, except make the block non-empty
块内的代码必须具有相同的缩进:
if x:
do_y()
do_z() # this needs to line up with do_y()
占据整行的注释在
#
标记前可以有任意数量的空格。文档字符串不是注释,并且必须按照与以下代码相同的方式缩进。
与开头语句对齐的第一行代码或较低级别的缩进位于块之外:
if x:
do_y()
do_z() # this happens regardless of the x value
# cannot write `else`: here; that is a syntax error
for i in range(10):
if x:
do_y()
do_z() # both the `if` and `for` blocks are ended
Python将制表符解释为扩展到下一个第 8 列;但在 3.x 中,混合空格和制表符的缩进必须具有完全相同的模式才能算作相同的缩进(并且进一步缩进需要具有相同的模式作为前缀)。如果做不到这一点,将导致
TabError
。while
Python 中的andfor
循环可能有一个else
子句,该子句在循环正常完成时执行,而不是通过break
。这是逻辑错误的常见来源:
for i in range(10):
if i % 2:
print(f'{i} is odd')
else: # wrongly indented
print(f'{i} is even') # only happens once, and claims 9 is even!
解决方案 4:
Python 2 的历史记录
默认情况下,Python 2 允许混合使用制表符和空格,并且默认情况下不会产生错误。将该-tt
选项传递给 Python 2.x 会导致它在与 3.x 相同的情况下引发异常,而是-t
引发警告。完整的详细信息请参阅Python 对制表符和空格缩进的解释。
特别要注意的是,制表符被视为8 个空格(相反,它们实际上将感知的空格数增加到 8 的下一个倍数)。因此,如果您使用标准的 4 个空格缩进显示代码,但混合使用空格和制表符,您最终可能会得到满足缩进规则的代码,但不会被视为按其外观缩进。
因此,你可能会得到各种其他错误。例如:
# in 2.x
def example():
def nested(): # suppose this is indented with a tab
x = [1] # and this with two tabs
print x[0] + 1 # but this with 8 spaces instead of a tab
nested()
(请注意,即使我使用制表符, Stack Overflow 的 Markdown 渲染也会将缩进显示为空格。)
这样就得到了一个NameError
,因为print x
不再位于nested
函数内部,并且x
超出了 外部 的范围。同样,我们可以通过给出一个 local ,或者给它一个 local ,example
轻松地创建一个。TypeError
`examplex = 1
ValueError`x = []
解决方案 5:
您看,您犯了一个小错误。
if True:
if False:
print('foo')
print('bar')
你应该这样做:
if True:
if False:
print('foo')
print('bar')
如您所见,您的打印仅缩进三个空格,但需要缩进四个空格才能与同一级别(if
语句)上的前一个缩进对齐。
解决方案 6:
Sublime Text用户的快速修复:
按
Ctrl
+H
访问“查找和替换”在“查找”中:输入四个空格
在替换中:从代码中的某个位置复制并粘贴一个标签。单击全部替换
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件