【问题标题】:I'm getting an IndentationError. How do I fix it?我得到一个缩进错误。我如何解决它?
【发布时间】:2022-09-07 09:45: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

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

  • 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:。如果您需要关闭 OP 执行此操作的问题,请参阅 Else clause on Python while statement

【问题讨论】:

  • 如果有人对此大惊小怪……只需在 Meta Stack Overflow 上发布一个关于它的问题。那是最好的讨论这个问题是否合适的地方,即使它完全适合作为欺骗目标。
  • 另一种观点:我不认为大多数缩进问题是拼写错误,所以我会继续欺骗关闭它们,我可能会将其用作欺骗目标。

标签: python exception error-handling indentation code-formatting


【解决方案1】:

为什么缩进很重要?

在 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 -- the Python style guide -- says:

每个缩进级别使用 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 touches on this topic:

空格是首选的缩进方法。

制表符应仅用于与已使用制表符缩进的代码保持一致。

但是请注意,一个重要的警告是不要同时使用两个标签缩进空间.这样做会导致各种奇怪的难以调试的缩进错误。 Python expands tabs to the next 8th column,但如果您的编辑器设置为 4 列的制表符大小,或者您使用空格和制表符,您可以轻松生成缩进代码看起来在你的编辑器中很好,但 Python 会拒绝运行。 Python 3 编译器明确的拒绝任何包含不明确的制表符和空格混合的程序,通常通过引发TabError。但是,默认情况下,Python 2 中仍然允许混合制表符和空格,但强烈建议不要使用此“功能”。使用 -t-tt 命令行标志来强制 Python 2 分别发出警告或(最好)错误。 PEP8 also discusses this topic:

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

在此示例中,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.
... 

“IndentationError:期望缩进块”是什么意思?

(这也可能在 Python 3.8 或更低版本中以 SyntaxError: unexpected EOF while parsing 的形式出现。)

问题

当 Python 看到复合语句的“标题”时会发生此错误,例如 if &lt;condition&gt;:while &lt;condition&gt;: 但复合语句的主体或堵塞从未定义。例如,在下面的代码中,我们开始了 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 期望一个或多个语句作为占位符的任何地方使用。 From the documentation for pass:

pass 是一个空操作——当它被执行时,什么也没有发生。当语法上需要语句但不需要执行任何代码时,它可用作占位符,例如:

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

“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

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

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

特别案例

注意 Python将不会 总是如果您在程序中混合制表符和空格,请提出TabError。如果程序缩进是明确的,Python 将允许混合制表符和空格。例如:

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

有时 Python 只是在制表符和空格的混合中窒息,并在 TabError 更合适时错误地引发 IndentationError 异常。另一个例子:

>>> 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 键)的次数。例如,如果您需要将一行缩进四个空格,您会大声说“,,,” 同时每次同时按下空格键。这听起来很傻,但它有助于训练你的大脑思考你的代码缩进有多深。
  • 如果您有编辑器,请查看它是否具有自动将制表符转换为空格的选项。
  • 查看其他人的代码。浏览 githubStackoverflow 并查看 Python 代码示例。
  • 只需编写代码。这是变得更好的唯一最佳方法。你写的 Python 代码越多,你就会越好。

使用的资源

【讨论】:

  • Here's a demo of not-TabError 和 here's a demo,其中 Python 根本不会为混合制表符和空格引发异常,因为它认为混合是明确的。
  • 请注意,函数 (def) 是复合语句,其文档字符串(如果有)需要作为其块的一部分缩进。我见过几个这样的问题。
【解决方案2】:

崇高的文字 3

如果您在 Sublime Text 3 中编写代码,这可以帮助您解决缩进问题

在 Sublime Text 中,编辑 Python 文件时:

崇高的文本菜单>喜好>设置 - 特定语法

Python.sublime-settings

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

【讨论】:

    【解决方案3】:

    你看,你有一个小错误。

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

    你应该这样做:

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

    如您所见,您的打印仅缩进 3 个空格,它应该缩进 4 个空格。

    【讨论】:

      【解决方案4】:

      Python 2 的历史注释

      默认情况下,Python 2 允许混合制表符和空格,除非将 -t-tt 选项传递给 Python,否则不会产生错误。完整的详细信息在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()
      

      (注意 Stack Overflow 的 Markdown 渲染 will show the indentation as spaces even if I use tabs。)

      这给出了NameError,因为print x 不再在nested 函数内,而x 超出了外部example 的范围。类似地,我们可以通过给example 一个本地x = 1 或通过给它一个本地x = [] 来轻松创建ValueError

      【讨论】:

        【解决方案5】:

        Sublime 用户的快速修复:

        1. 按 Ctrl-H 访问查找和替换
        2. 在查找中:键入 4 个空格
        3. 在替换中:从代码中的某处复制并粘贴选项卡 点击全部替换

        【讨论】:

        • 您实际上应该做相反的事情 - 搜索制表符(正则表达式转义字符 )并将它们替换为 4 个空格。见PEP 8 -- The Style Guide for Python Code。 Sublime 也有View → Indentation → Convert Indentation to Spaces菜单选项。
        猜你喜欢
        • 2018-01-19
        • 2018-03-09
        • 2021-09-19
        • 1970-01-01
        • 2019-10-07
        • 2022-09-30
        相关资源
        最近更新 更多