🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

精通Python的异常处理(try-except)

要在电脑上通过命令提示符或 PowerShell 运行 Python,需要先下载并安装 Python。
如果你还没有安装,请参考Python安装与开发环境配置一文来完成安装。

在编写程序时,遇到意想不到的错误是不可避免的。错误的原因多种多样,例如用户输入错误、文件不存在、网络问题等。在这种情况下,“异常处理”是一种可以防止程序突然崩溃并智能应对的机制。

本文将通过可立即复制粘贴并运行的代码示例,为初学者通俗易懂地解说Python中try-except语句在异常处理中的基本用法和进阶应用。让我们一边体验“让代码跑起来”的乐趣,一边掌握编写健壮程序的方法吧!


从基础开始!try-except语法

异常处理最基本的形式是try-except语句。顾名思义,它创建了一个“try(尝试),如果发生异常(错误),就except(捕获并处理)”的流程。

语法非常简单:

  1. try代码块中,编写可能会引发错误的代码。
  2. except代码块中,编写当错误发生时希望执行的代码。

百闻不如一见。让我们以著名的“除零错误”(ZeroDivisionError)为例。下面的代码试图将10除以0。通常情况下,这会导致程序因错误而停止,但通过try-except,我们可以妥善地捕获它。


<!-- Python代码 -->
try:
  # 可能会发生错误的代码
  result = 10 / 0
  print(f"计算结果: {result}")
except ZeroDivisionError:
  # 发生ZeroDivisionError时的处理
  print("哦!不能除以0。")

print("程序已正常结束。")
    

捕获特定异常!多个except

在程序中,可能会发生各种类型的错误。例如,在用户输入中,“希望输入数字却输入了字符串”(ValueError),或在文件操作中,“找不到指定的文件”(FileNotFoundError)等。

通过在except语句后指定错误的类型(异常类),可以只捕获特定的错误,并对每种错误执行相应的处理。

此外,通过并列多个except,可以根据错误类型编写不同的处理逻辑。以下示例尝试将字符串转换为整数。


<!-- Python代码 -->
user_input = "hello" # 不是数字而是字符串

try:
  num = int(user_input)
  print(f"输入的数字: {num}")
except ValueError:
  print("请输入数字!字符串无法转换为数字。")
except TypeError:
  print("类型错误!该类型不能转换为数字。")

print("继续执行处理...")
    

很多时候,我们希望了解发生的错误的详细信息(错误消息)。在这种情况下,可以使用as将异常对象存储在变量中。通常,变量名e(error或exception的首字母)被广泛使用。


<!-- Python代码 -->
try:
  # 尝试打开一个不存在的文件
  with open("不存在的文件.txt", "r") as f:
    content = f.read()
except FileNotFoundError as e:
  # 显示错误的详细信息
  print(f"找不到文件。")
  print(f"错误详情: {e}")

    

进阶篇:熟练使用else和finally

try-except还有两个强大的伙伴:elsefinally。将它们结合起来,可以实现更精细的处理。

让我们来看一个使用了所有这些元素的代码。


<!-- Python代码 -->
file_path = "my_data.txt"
data_to_write = "这是测试数据。"

try:
  print(f"正在向'{file_path}'写入数据...")
  f = open(file_path, "w", encoding="utf-8")
  # 如果想故意引发错误,请取消下一行的注释
  # f.write(12345) # 尝试写入非字符串内容会引发TypeError
  f.write(data_to_write)
  print("已尝试写入。")

except TypeError as e:
  print(f"发生错误!写入的数据必须是字符串。")
  print(f"错误详情: {e}")

except Exception as e:
  # 捕获其他意想不到的错误
  print(f"发生了意想不到的错误。")
  print(f"错误详情: {e}")

else:
  # 在try代码块没有发生异常时执行
  print("文件写入成功!")

finally:
  # 无论是否发生异常,总会执行
  if 'f' in locals() and not f.closed:
    f.close()
    print("文件已关闭。")
  else:
    print("文件未打开或已关闭。")

print("--- 处理完成 ---")
    

实践!可直接复制粘贴运行的完整代码示例

现在,让我们运用到目前为止所学的所有知识,来创建一个更实用的程序。此代码会询问用户的年龄,并重复提示直到输入有效的数字为止。然后,它会将输入的年龄保存到文件中。在此过程中可能发生的错误都由try-except处理。

请将下面的全部代码复制并保存为一个名为age_logger.py的文件,然后在终端中通过python age_logger.py来运行它。您可以故意输入一些字符,看看错误处理是如何工作的!


<!-- 完整的Python脚本: age_logger.py -->
import datetime

def record_age():
    """
    一个询问用户年龄并将其记录到文件中的函数。
    处理输入验证和文件I/O错误。
    """
    while True:
        try:
            # 接收用户输入
            age_str = input("请输入您的年龄(数字): ")

            # 将字符串转换为整数
            age = int(age_str)

            # 检查负值或不切实际的年龄
            if age < 0 or age > 130:
                # 引发自定义错误 (raise)
                raise ValueError("年龄必须在0到130岁之间。")

            # 如果输入了有效年龄,则跳出循环
            break

        except ValueError as e:
            # 捕获int()转换失败或由raise引发的ValueError
            print(f"错误: {e}")
            print("请再次输入正确的数字。\n")

    # 记录到文件
    try:
        # 使用with语句会自动关闭文件,因此不需要finally来调用close()
        with open("age_log.txt", "a", encoding="utf-8") as f:
            timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            f.write(f"[{timestamp}] 记录的年龄: {age}岁\n")
        
        print(f"您的年龄“{age}岁”已记录到'age_log.txt'中。")

    except IOError as e:
        # 捕获诸如没有文件写入权限之类的错误
        print("致命错误:无法写入文件。")
        print(f"错误详情: {e}")

if __name__ == "__main__":
    record_age()
    print("感谢您的使用。")

    

注意事项:捕获过于宽泛的异常

异常处理虽然方便,但如果使用不当,反而会使程序中的问题更难被发现。特别需要注意的是捕获范围过广的异常。

不推荐:裸except

最糟糕的写法是不指定异常类的“裸except:”。它会无差别地捕获所有错误。这甚至包括用于终止程序的SystemExit,以及通过按Ctrl+C强制停止时产生的KeyboardInterrupt。这可能导致您想停止程序却无法停止的情况。

需注意:except Exception

except Exception as e:虽然比裸except:要好,但它仍然会捕获大多数常见的错误。在开发过程中,我们常常希望通过让错误发生来发现意想不到的bug。如果什么都捕获,那些本应被修复的bug就可能会被掩盖。

最佳实践是“只具体指定并捕获那些可预测且能妥善处理的异常”。


总结与后续步骤

这次,我们学习了Python中用于异常处理的try-except语句。让我们回顾一下要点:

  • 使用try-except可以防止程序因错误而崩溃。
  • 使用except ExceptionClass as e可以捕获特定错误并获取详细信息。
  • else用于处理成功时的情况,而finally用于执行清理工作。
  • 诀窍是将异常的捕获范围限制在具体且可处理的特定情况上,而不是过于宽泛。

掌握了异常处理,您就可以创建出对用户友好、对开发者易于维护的健壮应用程序。请务必在您的代码中引入try-except

作为下一步,何不学习一个能让程序模块化并提高其可重用性的重要概念呢?

>> 下一篇文章:Python类与面向对象编程入门