我有一个Python脚本:
if True: if False: print('foo') print('bar')
但是,当我尝试运行脚本时,Python会引发一个IndentationError:
IndentationError
File "script.py", line 4 print('bar') ^ IndentationError: unindent does not match any outer indentation level
我一直在玩我的程序,并且还能够产生其他三个错误:
这些错误是什么意思?我究竟做错了什么?如何修复我的代码?
缩进为何重要?
在Python中,缩进用于分隔代码块。这与许多其他使用花括号{}分隔块的语言(例如Java,Javascript和C)不同。因此,Python用户必须密切注意缩进代码的时间和方式,因为空格很重要。
Javascript
当Python遇到程序缩进问题时,它会引发一个称为IndentationError或的异常TabError。
TabError
一点历史
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
但是,你可能从上面可以看出,随机地缩进代码会使阅读和遵循程序流程变得非常困难。最好保持一致并遵循一种风格。
PEP8-Python样式指南-建议在每个缩进级别使用四个空格:
每个缩进级别使用4个空格。
也就是说,每个开始一个新块的语句以及该新块中的每个后续语句都应从当前缩进级别缩进四个空格。这是根据PEP8样式指南缩进的上述程序:
我还可以使用标签吗?
Python意识到有些人仍然喜欢使用制表符而不是空格,并且遗留代码可能使用制表符而不是空格,因此它允许使用制表符作为缩进。PEP8涉及以下主题:
空格是首选的缩进方法。
制表符应仅用于与已经用制表符缩进的代码保持一致。
但是请注意,最大的警告是不要同时使用制表符和空格进行缩进。这样做会导致各种奇怪的难以调试的缩进错误。Python将制表符扩展到下一个第8列,但是如果将编辑器的制表符大小设置为4列,或者你同时使用空格和制表符,则可以轻松生成缩进的代码,这些代码在编辑器中看起来不错,但是Python会拒绝跑步。Python 3编译器通常通过引发来显式拒绝包含制表符和空格的混合使用的程序TabError。但是,默认情况下,Python 2仍允许混合使用制表符和空格,但是强烈建议不要使用此“功能”。使用-t和-tt命令行标志分别强制Python 2发出警告或(最好是)错误。PEP8还讨论了以下主题:
-t
-tt
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,我们可以通过确保with can_drive = True所在行的缩进与if正文中先前语句的缩进级别来修复错误:
with can_drive = True
>>> age = 10 >>> can_drive = None >>> >>> if age >= 18: ... print('You can drive') ... can_drive = True # indent this line at the same level. ...
“ IndentationError:预期缩进的块”是什么意思? 问题
当Python看到复合语句的“标头”(例如if :或,while :但从未定义复合语句的主体或块)时,就会发生此错误。例如,在下面的代码中,我们开始了一条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语句可在Python需要一个或多个语句作为占位符的任何地方使用。从文档中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
很难捕获此错误,因为即使一个空格也会导致你的代码失败。
解决方法是确保取消对语句的缩进时,缩进级别与先前的语句匹配。再次考虑上述示例。在示例中,我希望第二个打印要在第一个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
这是一张图片,直观地显示了上述程序中的空白。灰色点是空格,灰色箭头是标签:
我们可以看到我们确实有混合的空格和缩进制表符。
特别案例
注意如果将制表符和空格混入程序中,Python 不会 总是产生a TabError。如果程序缩进是明确的,Python将允许制表符和空格混合使用。例如:
>>> if True: ... if True: # tab ... pass # tab, then 4 spaces ... >>>
有时,Python只是在制表符和空格的混合中使人窒息,并IndentationError在a TabError更合适的情况下错误地引发了异常。另一个例子:
>>> if True: ... pass # tab ... pass # 4 spaces File "<stdin>", line 3 pass # 4 spaces ^ IndentationError: unindent does not match any outer indentation level
如你所见,以这种方式运行代码会产生神秘的错误。即使该程序在外观上看起来不错,但Python仍在尝试解析用于缩进的制表符和空格并出错时感到困惑。
这些都是出色的示例,这些示例说明了为什么在使用Python 2时永远不要混用制表符和空格并使用-t和-tt解释器标志。
如果你的程序简短,那么最简单,最快的解决方法就是简单地重新缩进该程序。确保每个语句在每个缩进级别缩进四个空格(请参阅如何缩进代码?)。
但是,如果你已经有将制表符和空格混入其中的大型程序,则可以使用自动化工具将所有缩进转换为仅空格。
许多编辑器(例如PyCharm和SublimeText)都具有将制表符自动转换为空格的选项。还有一些在线工具,例如“ 制表符到空格”或“ 浏览器”,可让你快速重新缩进代码。还有一些用Python编写的工具。例如,autopep8可以自动重新缩进你的代码以及其他缩进错误。
即使是最好的工具,有时也无法修复所有的缩进错误,因此你必须手动修复它们。这就是为什么从一开始就始终正确缩进代码很重要的原因。
有关“ SyntaxError”的缩进问题的说明
尽管不经常使用,但有时SyntaxError由于缩进不正确会引起某些例外情况。例如,看下面的代码:
SyntaxError
if True: pass pass # oops! this statement should be indented!. else: pass
运行上面的代码后,一个SyntaxError is raised:
Traceback (most recent call last): File "python", line 4 else: ^ SyntaxError: invalid syntax
尽管Python提出了a SyntaxError,但是上面的代码的真正问题是第二条pass语句应该缩进。因为第二个pass没有缩进,所以Python并没有意识到前面的if语句和该else语句是要连接的。
Python
a SyntaxErro
pass
else
解决此类型错误的方法是简单地正确缩进你的代码。要查看如何正确缩进代码,请参见如何缩进代码部分。。
我仍然很难使用Python的缩进语法。我该怎么办?
如果你仍在挣扎,不要灰心。使用Python的空白语法规则可能需要一些时间。这里有一些技巧可以帮助你: