python 我收到IndentationError,如何修复它?

to94eoyn  于 2023-04-10  发布在  Python
关注(0)|答案(6)|浏览(199)

我有一个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

我一直在玩我的程序,我总共产生了四个错误:

  • 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

这些错误意味着什么?我做错了什么?我如何修复我的代码?

**注意:**这是一个canonical question的尝试,因为我每个月都会看到很多类似的帖子。这不是关于unindentsunexpected indents的现有问题的重复,因为它们只处理一种类型的缩进错误,我希望在一个地方涵盖它们。

也有可能出现逻辑上不正确的缩进,但不会导致错误消息。一种常见的形式是将else:附加到forwhile循环中,而不是(如预期的那样)相应的if:。如果需要关闭问题,请参阅Else clause on Python while statement
请参阅How to fix Python indentation,了解更多清理缩进以符合标准的工具和技术(即使它已经“工作”)。

laximzn5

laximzn51#

为什么缩进很重要?

在Python中,缩进用于分隔blocks of code。这与许多其他使用花括号{}分隔块的语言(如Java,Javascript和C)不同。因此,Python用户必须密切注意何时以及如何缩进代码,因为空格很重要。
当Python遇到程序缩进问题时,它会引发一个名为IndentationErrorTabError的异常。

一段历史

Python使用缩进而不是更普遍接受的花括号{}的历史原因在an article of the history of Python by Guido van Rossum中概述-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个空格。
也就是说,每个开始新块的语句和新块中的每个后续语句,都应该从当前缩进级别缩进四个空格。下面是根据PEP 8样式指南缩进的上述程序:

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意识到有些人仍然喜欢制表符而不是空格,并且遗留代码可能使用制表符而不是空格,因此它允许使用制表符作为缩进。PEP 8涉及到这个主题:
空格是首选的缩进方法。
制表符只能用于与已使用制表符缩进的代码保持一致。
注意,一个很大的警告是不要同时使用制表符 * 和 * 空格进行缩进。这样做会导致各种奇怪的难以调试的缩进错误。Python expands tabs to the next 8th column,但是如果你的编辑器设置为4列的制表符大小,或者你使用空格和制表符,你可以很容易地产生缩进代码,在你的编辑器中看起来很好。但Python会拒绝运行。Python 3编译器 * 显式 * 拒绝任何包含不明确的制表符和空格混合的程序,通常是通过引发TabError。然而,默认情况下,Python 2仍然允许混合制表符和空格,但强烈建议不要使用这个“特性”。使用-t-tt命令行标志来强制Python 2分别引发警告或(最好)错误。PEP 8也讨论了这个主题:
Python 3不允许在缩进中混合使用制表符和空格。
Python 2代码中混合使用制表符和空格的缩进应该转换为只使用空格。
当使用-t选项调用Python 2命令行解释器时,它会发出关于非法混合制表符和空格的代码的警告。当使用-tt时,这些警告会变成错误。强烈推荐使用这些选项!

“缩进错误:意外缩进”是什么意思

问题

当一个语句被不必要地缩进或其缩进与同一块中以前语句的缩进不匹配时,就会发生此错误。例如,下面程序中的第一个语句被不必要地缩进:

>>>  print('Hello') # this is indented 
  File "<stdin>", line 1
    print('Hello') # this is indented 
    ^
IndentationError: unexpected indent

在本例中,if块中的can_drive = True行与前面任何语句的缩进都不匹配:

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

“缩进错误:预期缩进块”是什么意思

(This在Python 3.8或更低版本中也可能出现为SyntaxError: unexpected EOF while parsing。)

问题

当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语句可以在Python需要一个或多个语句作为占位符的任何地方使用。从pass的文档中可以看到:
pass是一个null操作-当它被执行时,什么都不会发生。当语法上需要一个语句,但不需要执行任何代码时,它作为占位符很有用,例如:

def f(arg): pass    # a function that does nothing (yet)

class C: pass       # a class with no methods (yet)

下面是上面的示例,其中使用pass关键字修复了if语句:

>>> if True:
...     pass # We don't want to define a body.
... 
>>>

“缩进错误: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

下面的图片直观地显示了上面程序中的空白。灰色的点是空格,灰色的箭头是制表符:

我们可以看到,我们确实混合了空格和制表符用于缩进。

特殊情况

注意如果你在程序中混合使用制表符和空格,Python***不会***总是 * 引发TabError。如果程序缩进是明确的,Python将允许制表符和空格混合使用。例如:

>>> if True:
...     if True: # tab
...         pass # tab, then 4 spaces
... 
>>>

有时候Python会因为制表符和空格的混合而阻塞,错误地抛出IndentationError异常,而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解释器标志。

修复

如果你的程序很短,可能最简单和最快的解决方法就是简单地重新缩进程序。确保每个语句在每个缩进级别缩进四个空格(参见***如何缩进代码?***)。
但是,如果你已经有一个混合了制表符和空格的大型程序,那么可以使用自动化工具将所有缩进转换为空格。

许多编辑器,如PyCharmSublimeText都有自动将制表符转换为空格的选项。还有一些在线工具,如Tabs To SpacesBrowserling,可以让你快速重新缩进代码。还有一些用Python编写的工具。例如,autopep8可以自动重新缩进代码并修复其他缩进错误。
即使是最好的工具,有时也不能修复所有的缩进错误,你必须手动修复它们。这就是为什么从一开始就正确缩进你的代码是很重要的。

关于“SyntaxError”相关缩进问题的说明

虽然不经常,但有时由于不正确的缩进会引发某些SyntaxError异常。例如,请看下面的代码:

if True:
    pass
pass # oops! this statement should be indented!.
else:
    pass

当上面的代码运行时,会引发SyntaxError

Traceback (most recent call last):
  File "python", line 4
    else:
       ^
SyntaxError: invalid syntax

虽然Python抛出了一个SyntaxError,但上面代码的真实的问题是第二个pass语句应该缩进。因为第二个pass不是缩进的,所以Python没有意识到前面的if语句和else语句是要连接的。
解决这类错误的方法是正确地重新缩进代码。要了解如何正确缩进代码,请参阅***如何缩进代码?***一节。

Python的缩进语法我还是不太懂,怎么办?

如果你还在挣扎,不要气馁。习惯Python的空格语法规则可能需要时间。这里有一些提示可以帮助你:

  • 得到一个编辑器,当你有一个缩进错误时,它会告诉你。一些好的编辑器如上所述是,PyCharmSublimeTextJupyter Notebook
  • 当你缩进代码的时候,大声地数出你按了多少次空格键(或者tab键)。例如,如果你需要缩进一行四个空格,你会大声地说“onetwothreefour”,同时每次都按空格键。这听起来很傻,但它有助于训练你的大脑思考你缩进代码的深度。
  • 如果你有一个编辑器,看看它是否有一个选项,自动转换制表符到空格。
  • 查看其他人的代码。浏览githubStackoverflow并查看Python代码示例。
  • 只要写代码。这是变得更好的唯一最好的方法。你写的Python代码越多,你就会变得越好。

使用资源

wsewodh2

wsewodh22#

Sublime Text 3

如果您使用Sublime Text 3编写代码,这可以帮助您解决缩进问题
在Sublime Text中,编辑Python文件时:

Sublime Text菜单首选项设置-特定语法
Python.sublime-settings

{
    "tab_size": 4,
    "translate_tabs_to_spaces": true
}
voase2hg

voase2hg3#

你看,你有一个小错误。

if True:
    if False:
        print('foo')
   print('bar')

你应该做:

if True:
    if False:
        print('foo')
    print('bar')

正如你所看到的,你的打印只缩进了3个空格,它应该缩进4个空格。

zte4gxcn

zte4gxcn4#

Python 2历史说明

默认情况下,Python 2允许制表符和空格混合使用,并且默认情况下不会产生错误。将-tt选项传递给Python 2.x会导致它在3.x相同的情况下引发异常,而-t会导致警告。完整的细节在Python's interpretation of tabs and spaces to indent中解释。
特别要注意的是,制表符被视为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()

(Note Stack Overflow的Markdown渲染will show the indentation as spaces even if I use tabs
这样就得到了一个NameError,因为print x不再在nested函数内部,而x超出了外部example的作用域。类似地,我们可以通过给example一个本地x = 1来轻松创建一个TypeError,或者通过给它一个本地x = []来创建ValueError

wrrgggsh

wrrgggsh5#

快速检查表

  • 不正确的缩进最常导致IndentationError,但也可能导致TabErrorIndentationError的子类型)或SyntaxError(缩进本身是法律的的,但它会导致其他代码出现语法错误)。对于Python代码有效但不符合程序员意图的缩进会导致逻辑错误(代码不会引发异常,但会出错)。
    *强烈建议不要使用制表符进行缩进。在Python 2.x中,使用-tt命令行参数运行Python会引发相同的TabError,这对查找问题很有用。
  • PEP 8中,社区标准是每一级缩进使用四个空格。
  • iffordefclass这样以冒号:结尾的语句,后面需要一个 * 缩进块 *:
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
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!
2ledvvac

2ledvvac6#

Sublime用户的快速修复:
1.按Ctrl-H访问“查找和替换”
1.在查找中:键入4个空格
1.替换:从代码中的某处复制并粘贴选项卡单击“全部替换”

相关问题