10 种常见的 Python 错误类型及其解决方法

在软件开发的旅程中,作为一名程序员,你必然会与各种错误不期而遇。这些错误可能源于逻辑上的偏差,导致程序产生非预期的结果;也可能违反了编程语言自身的规则,引发运行时错误。 简而言之,这些“拦路虎”都被我们统称为错误。

错误是编程世界中普遍存在的现象,它们并不因编程语言的易用性而有所减少。 即使是那些被认为简单易学的语言,也不能完全避免错误的发生。

例如,Python 以其强调可读性的特点,以及简洁的语法而闻名,相较于其他编程语言更容易上手。 然而,在使用 Python 进行编程时,你仍然无法完全避免编程错误的出现。

既然错误是不可避免的,那么积极地认识并理解各种错误的成因就显得至关重要。 这不仅能帮助你在编程时有效规避或最大程度地减少错误的发生,还能让你在错误出现时知道如何从容应对。

以下是一些在 Python 编程中你可能遇到的常见错误类型:

语法错误

当你编写的代码不符合所使用编程语言的语法规则时,就会发生语法错误。 这会导致代码行无效,程序无法正确执行。

比如,在 Python 中,当你要打印一个字符串时,需要将其用引号括起来。 如果你忘记这样做,就会产生语法错误。

此外,当你遗漏了左括号、右括号、方括号或花括号,关键字或函数名拼写错误,流程控制语句末尾缺少冒号,或者表达式中缺少必要的操作符时,也都会出现语法错误。

简而言之,任何违反 Python 代码编写规则的行为,都可能导致语法错误。

  ## 缺少引号导致的语法错误
  print("Hello World)

  age = 20
  ## if 语句中缺少冒号导致的语法错误
  if age > 18
      print("年龄大于 18 岁")

  ## 未闭合的括号导致的语法错误
  def square(x:
    return x * x
  print(square(4))

运行上述代码后,你将会看到类似以下的错误信息:

错误提示:

  File "/home/madici/Desktop/helloworld.py", line 1
    print("Hello World)
          ^
  SyntaxError: unterminated string literal (detected at line 1)

要解决这些错误,需要遵循正确的 Python 语法,修改后的代码如下:

  print("Hello World")

  age = 20
  if age > 18:
      print("年龄大于 18 岁")

  def square(x):
      return x * x
  print(square(4))

缩进错误

与其他使用大括号(例如 Java、C 或 C++)来分隔代码块的语言不同,Python 使用缩进来定义代码块的层级结构。 例如,在 Java 中,控制语句内的代码会使用大括号括起来。

而在 Python 中,代码块通过缩进来定义。 Python 中典型的缩进通常是四个空格或一个制表符。 只要在代码中保持一致,空格的数量并不重要。

作为一名 Python 程序员,你可能会因为未能正确添加缩进,而遇到缩进错误。 例如,在编写控制语句或函数时,不一致地使用制表符和空格会导致缩进错误;或者在错误的位置放置缩进,以及在整个代码库中缩进不一致都会引发此类错误。

以下是导致缩进错误的代码示例:

  age = 20
  if age > 18:
  print("年龄大于 18 岁")
    print("你可以开车了")
  else:
    print("年龄小于 18 岁")

上述代码产生的错误信息如下:

错误提示:

  File "/home/madici/Desktop/helloworld.py", line 3
    print("年龄大于 18 岁")
    ^
  IndentationError: expected an indented block after 'if' statement on line 2

要修正错误,需要在 if 语句后的代码行进行缩进,确保它与代码其余部分的缩进一致,修改后的代码如下所示:

  age = 20
  if age > 18:
    print("年龄大于 18 岁")
    print("你可以开车了")
  else:
    print("年龄小于 18 岁")

类型错误

在 Python 中,当尝试对不兼容的数据类型执行操作时,会发生 TypeError 错误。 例如,尝试将一个字符串和一个整数相加,或将一个字符串数据类型与一个整数进行连接,都会引发 TypeError。

当使用具有错误数据类型的函数或方法时,当尝试使用非整数索引来访问列表等可迭代对象中的元素时,或者当尝试迭代一个不可迭代的对象时,也可能遇到 TypeError。

总而言之,任何使用错误数据类型执行的操作都可能导致 TypeError。

以下是可能导致类型错误的操作示例:

  # 将字符串和整数连接时导致的类型错误
  age = 25
  message = "我今年 " + age + " 岁。"

  list1 = [1, "你好", 5, "世界", 18, 2021]
  # 内置方法使用错误导致的类型错误
  print(sum(list1))

  # 字符串和整数相加导致的类型错误
  num1 = 10
  num2 = "16"
  print(num1 + num2)

  # 使用非整数索引导致的类型错误
  list2 = ["你好", "来自", "另一", "边"]
  print(list2["1"])

上述代码产生的错误信息如下:

代码中的 TypeError 错误消息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 3, in <module>
      message = "我今年 " + age + " 岁。"
                ~~~~~~~~^~~~~
  TypeError: can only concatenate str (not "int") to str

要消除错误,需要使用正确的数据类型或者进行类型转换,修改后的代码如下所示:

  age = 25
  message = "我今年 " + str(age) + " 岁。"

  list1 = [1, 5, 18, 2021]
  print(sum(list1))

  num1 = 10
  num2 = "16"
  print(num1 + int(num2))

  list2 = ["你好", "来自", "另一", "边"]
  print(list2[1])

属性错误

在 Python 中,当你尝试访问对象上不存在的属性或调用对象上不存在的方法时,会发生 AttributeError。 AttributeError 表明对象没有被调用的属性或方法。

例如,如果你对一个整数调用字符串方法,就会遇到 AttributeError,因为该方法在你调用的对象类型上不存在。

在以下示例中,用于将字符串的第一个字母转换为大写的 `capitalize()` 方法被调用在一个整数上。 这会产生属性错误,因为整数没有 `capitalize()` 方法。

  # 对整数调用 capitalize() 方法导致的属性错误
  num = 1445
  cap = num.capitalize()
  print(cap)

运行此代码会产生以下错误信息:

代码中的 AttributeError 消息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 3, in <module>
      cap = num.capitalize()
            ^^^^^^^^^^^^^^
  AttributeError: 'int' object has no attribute 'capitalize'

要解决 AttributeError,请确保调用的方法或属性存在于你调用它的对象类型上。 在这种情况下,对字符串数据类型调用 `capitalize()` 方法可以解决此错误,如下所示:

导入错误

当尝试导入当前环境中不存在或无法访问的模块时,Python 中会发生 ImportError。 这可能是因为模块尚未安装,或者其路径配置不正确,也可能是你拼写错了要导入的模块名称。

ImportError 有一个名为 ModuleNotFoundError 的子类,当尝试导入一个无法找到的模块时,会抛出这个错误。

例如,下面的代码在尝试导入数据分析库 pandas 时会抛出这样的错误,因为该模块尚未安装。

生成的 ImportError 消息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 1, in <module>
      import pandas
  ModuleNotFoundError: No module named 'pandas'

要解决此类错误,请确保已安装你尝试导入的模块。 如果这不能解决问题,请检查模块名称是否拼写正确,以及文件路径是否正确。

值错误

当 Python 中的函数接收到正确数据类型的值,但该值不合适时,就会发生 ValueError。 例如,如果传入一个负数,用于计算数值平方根的 `Math.sqrt()` 函数会返回 ValueError。

虽然传入的值类型是正确的(数值),但负数使其成为不合适的值。

如果传入的字符串不是数字字符串值,那么用于转换数字或字符串的函数 `int()` 会返回 ValueError。 将“123”或“45”传递给函数不会返回错误,因为这些字符串可以转换为适当的整数值。

但是,如果传入的字符串不是数字字符串值(例如 “Hello”),则会返回 ValueError。 这是因为“Hello”虽然是一个字符串,但不合适,因为它没有等效的整数。

以下是产生 ValueError 的代码示例:

  # sqrt() 函数中传入不合适的整数值导致的错误
  import math
  num = -64
  root = math.sqrt(num)
  print(root)

  # int() 函数中传入非数字字符串值导致的错误
  numString = "Hello"
  num = int(numString)
  print(num)

上述代码的错误信息如下:

生成的错误信息如下:

  File "/home/madici/Desktop/helloworld.py", line 4, in <module>
      root = math.sqrt(num)
            ^^^^^^^^^^^^^^
  ValueError: math domain error

要更正错误,请在函数中使用适当的值,修改后的代码如下所示:

  import math
  num = 64
  root = math.sqrt(num)
  print(root)

  numString = "5231"
  num = int(numString)
  print(num)

IO错误

IOError (输入/输出错误) 是在输入或输出操作失败时发生的异常。 这可能是因为尝试访问不存在的文件、设备中的磁盘存储空间不足、尝试访问你没有足够权限访问的文件,或者当尝试访问当前正在被其他操作使用的文件时造成的。

处理文件时通常使用的 `open()`、`read()`、`write()` 和 `close()` 等方法很可能会导致此类错误。

以下代码尝试打开一个名为“notes.txt”的不存在的文件。 该代码会导致 IOError,从而引发 FileNotFoundError:

出现以下错误消息:

  File "/home/madici/Desktop/helloworld.py", line 2, in <module>
      file1 = open("notes.txt", "r")
              ^^^^^^^^^^^^^^^^^^^^^^
  FileNotFoundError: [Errno 2] No such file or directory: 'notes.txt'

为了避免上述错误,你需要确保“notes.txt”文件存在于你运行终端的目录中。另一种处理 IOErrors 的方法是使用 try except 块,如下所示:

名称错误

NameError 是当你尝试使用不存在、未在当前范围内定义或未赋值的变量、函数或模块时会遇到的异常。

当拼写错误变量或函数名称,或者在定义它们之前使用它们时,通常会发生此类错误。 在不导入模块的情况下使用模块也会导致 NameError。

以下代码会引发 NameError 异常:

  # 因为 math 模块未导入导致的名称错误
  num = 64
  root = math.sqrt(64)
  print(root)

  # 因为 x 在定义之前被使用而导致的名称错误
  y = 23
  print(x)

  # 因为函数名称未定义导致的名称错误
  def greet():
      print("早上好")
  great() #ameError: name 'great' is not defined

以下错误信息由上面的代码产生:

示例 NameError 消息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 3, in <module>
      root = math.sqrt(64)
             ^^^^
  NameError: name 'math' is not defined

要解决此类 NameError,请确保在导入模块之前没有使用模块,在定义变量或函数之前没有使用它们,并且没有拼写错误函数或变量的名称:

  import math
  num = 64
  root = math.sqrt(64)
  print(root)

  y = 23
  print(y)

  def greet():
      print("早上好")
  greet()

索引错误

IndexError 是当你尝试访问超出范围的列表或元组中的索引时发生的异常。 考虑下面的列表:

  list1 = [1, 2, 3, 4, 5]

该列表有五个元素。 Python 从 0(零)开始计算索引。 因此,上面列表的索引范围从 0 到 n-1,n 是列表中的数字或元素的数量。 在这种情况下,索引范围为 0 到 4。

如果尝试访问大于 4 的索引的元素,就会遇到 IndexError,因为该索引超出了你尝试从中访问元素的列表范围。 以下代码将生成 IndexError:

  list1 = [1, 2, 3, 4, 5]
  item = list1[6] # 索引超出范围导致的 IndexError
  print(item)

代码中的错误信息如下所示:

生成的 IndexError 信息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 2, in <module>
      item = list1[6] # 索引超出范围导致的 IndexError
             ~~~~~^^^
  IndexError: list index out of range

避免 IndexError 的最佳方法是使用 `range()` 和 `len()` 函数,确保只访问范围内的元素,如下所示:

  list1 = [1, 2, 3, 4, 5]

  for i in range(len(list1)):
      print(list1[i])

键错误

KeyError 是当你尝试使用字典中不存在的键来访问字典中的项目时发生的异常。 考虑下面的字典:

  cities = {"加拿大": "渥太华", "美国": "华盛顿", "意大利": "罗马"}

字典中的键是“加拿大”、“美国”、“意大利”。 你可以使用这三个键来访问城市字典中的项目。 但是,如果你尝试使用一个不存在的键来访问元素,例如“巴西”,就会遇到 KeyError,如下所示:

生成的 KeyError 信息如下所示:

  File "/home/madici/Desktop/helloworld.py", line 6, in <module>
    print(cities["巴西"])
          ~~~~~~^^^^^^^^^^
  KeyError: '巴西'

要解决 KeyError,请确保你用于访问字典中元素的键确实存在于字典中。 为此,可以使用 if…else 语句,如下所示:

  cities = {"加拿大": "渥太华", "美国": "华盛顿", "意大利": "罗马"}

  country = "加拿大"

  if country in cities:
      print("“" + country + "”的首都城市是“" + cities[country] + "”")
  else:
    print("字典中不存在键“" + country + "”")

这样,就可以避免在访问字典中的元素时遇到 KeyErrors

结论

在使用 Python 进行编程时,无论你的专业水平如何,都一定会遇到错误。 因此,请务必熟悉本文中提到的不同类型的错误,以便能够在它们出现时及时处理。

你还可以探索一些有用的 Python 单行代码来简化常见任务。