当前位置:首页>python>Python3 错误和异常:别怕报错,那是程序在跟你说话

Python3 错误和异常:别怕报错,那是程序在跟你说话

  • 2026-09-30 17:38:06
Python3 错误和异常:别怕报错,那是程序在跟你说话

Python3 错误和异常:别怕报错,那是程序在跟你说话

我是陈默,一个正拼命上岸的码农。

你写代码最怕什么?

报错。

红色的错误信息一出来,心跳加速,手心冒汗。

但说实话——报错不是坏事。那是程序在跟你说话。它在告诉你:"嘿,这里有问题,你得修一下。"

真正可怕的不是报错,是你的代码默默跑完,结果全是错的。

今天我们来聊聊 Python 的错误和异常处理。学会它,你的代码就不会因为一个小意外就崩溃。


1. 两种错误:语法错误和异常

语法错误(SyntaxError)

代码写错了,Python 看不懂。

# 少了冒号ifTrue    print("hello")# SyntaxError: expected ':'# 括号没配对print("hello"# SyntaxError: unexpected EOF while parsing# 缩进错误deffunc():print("hello")# IndentedError: expected an indented block

语法错误在运行前就能发现。修复很简单——看报错行号,回去改。

异常(Exception)

语法没问题,但运行时出了状况。

print(1 / 0)         # ZeroDivisionError:除以零print(undefined_var)  # NameError:变量不存在int("abc")           # ValueError:转换失败lst = [1, 2, 3]print(lst[10])       # IndexError:索引越界d = {"name": "陈默"}print(d["age"])      # KeyError:键不存在

异常才是我们今天要重点讲的——因为它是可以被处理的。


2. try-except:捕获异常

基本用法

try:    result = 10 / 0except ZeroDivisionError:    print("不能除以零")print("程序继续运行")    # 输出: 程序继续运行

没有 try-except,程序直接崩溃。有了它,程序优雅地处理问题,继续往下走。

捕获多种异常

try:    num = int(input("输入数字:"))    result = 100 / num    print(f"结果:{result}")except ValueError:    print("请输入有效的数字")except ZeroDivisionError:    print("不能除以零")

捕获所有异常

try:# 一些可能出错的代码    result = do_something()except Exception as e:    print(f"出错了:{e}")

注意:except Exception 可以捕获所有异常,但别滥用。

# ❌ 万能捕获,出问题了都不知道为什么try:    result = complex_operation()except:pass# 吞掉所有错误,非常危险# ✅ 明确捕获你知道的异常try:    result = int(user_input)except ValueError:    print("输入格式错误")

获取异常信息

try:    result = 10 / 0except ZeroDivisionError as e:    print(f"错误类型:{type(e).__name__}")    # 输出: 错误类型:ZeroDivisionError    print(f"错误信息:{e}")                     # 输出: 错误信息:division by zero

3. try-except-else-finally:完整的结构

try:# 可能出错的代码    f = open("data.txt", "r")    content = f.read()except FileNotFoundError:# 出错时执行    print("文件不存在")else:# 没出错时执行    print(f"文件内容:{content}")finally:# 不管出不出错都执行    print("清理工作完成")

执行逻辑:

  • try → 正常代码
  • except → 出错了才走
  • else → 没出错才走
  • finally → 一定走

finally 的常见用途:清理资源

try:    f = open("data.txt", "r")    content = f.read()finally:    f.close()    # 不管出不出错,都关闭文件

不过我们之前学过,用 with 更好:

with open("data.txt", "r") as f:    content = f.read()    # 自动关闭,不用 finally

4. 常见异常类型

异常
说明
触发场景
ZeroDivisionError
除以零
1 / 0
ValueError
值不对
int("abc")
TypeError
类型不对
"2" + 2
IndexError
索引越界
[1,2][5]
KeyError
键不存在
{}["x"]
NameError
变量未定义
print(x)
FileNotFoundError
文件不存在
open("xx")
AttributeError
属性不存在
"hi".appendd()
ImportError
导入失败
import 不存在的模块

实际例子

# TypeError:类型不对print("年龄:" + 25)          # 报错!字符串不能直接加数字print("年龄:" + str(25))     # 输出: 年龄:25# AttributeError:方法名写错name = "陈默"print(name.uppper())          # 报错!没有 uppper 方法print(name.upper())           # 输出: 陈默# IndexError:索引越界nums = [1, 2, 3]print(nums[5])                # 报错!只有 3 个元素

5. 主动抛出异常:raise

有时候你自己需要抛出异常。

基本用法

defset_age(age):if age < 0:raise ValueError("年龄不能为负数")if age > 150:raise ValueError("年龄不太对吧?")return agetry:    set_age(-5)except ValueError as e:    print(e)    # 输出: 年龄不能为负数

自定义异常

classInsufficientFundsError(Exception):"""余额不足异常"""def__init__(self, balance, amount):        self.balance = balance        self.amount = amount        super().__init__(f"余额不足:余额 {balance} 元,尝试取出 {amount} 元")classBankAccount:def__init__(self, balance=0):        self.balance = balancedefwithdraw(self, amount):if amount > self.balance:raise InsufficientFundsError(self.balance, amount)        self.balance -= amountreturn self.balance# 使用account = BankAccount(100)try:    account.withdraw(200)except InsufficientFundsError as e:    print(e)         # 输出: 余额不足:余额 100 元,尝试取出 200 元except Exception as e:    print(f"其他错误:{e}")

自定义异常让你的代码更专业。别人调用你的函数时,能清楚地知道出了什么问题。


6. 异常链:从底层到上层

defread_config():try:with open("config.json", "r") as f:return f.read()except FileNotFoundError as e:# 把底层异常包装成更有意义的异常raise RuntimeError("配置文件缺失,请检查") from etry:    config = read_config()except RuntimeError as e:    print(e)           # 输出: 配置文件缺失,请检查    print(e.__cause__)  # 输出: [Errno 2] No such file or directory: 'config.json'

raise ... from e 保留了原始异常信息,方便排查问题。


7. 常见场景:异常处理最佳实践

场景一:用户输入

defget_int(prompt):"""安全地获取整数输入"""whileTrue:try:return int(input(prompt))except ValueError:            print("请输入有效的整数")age = get_int("请输入年龄:")print(f"你的年龄:{age}")

场景二:文件操作

defsafe_read(filepath):"""安全地读取文件"""try:with open(filepath, "r", encoding="utf-8") as f:return f.read()except FileNotFoundError:        print(f"文件不存在:{filepath}")returnNoneexcept PermissionError:        print(f"没有权限读取:{filepath}")returnNoneexcept UnicodeDecodeError:        print(f"文件编码错误:{filepath}")returnNonecontent = safe_read("data.txt")if content:    print(content)

场景三:网络请求

deffetch_data(url, retries=3):"""带重试的网络请求"""import timefor attempt in range(retries):try:# 模拟请求if url == "success":return {"status": "ok"}else:raise ConnectionError("连接失败")except ConnectionError as e:if attempt < retries - 1:                print(f"第{attempt + 1}次失败,1秒后重试...")                time.sleep(1)else:                print(f"重试{retries}次后仍然失败")raisetry:    data = fetch_data("fail")except ConnectionError:    print("请检查网络连接")

8. 实战:带异常处理的成绩管理器

classScoreManager:def__init__(self):        self.scores = {}defadd(self, name, score):ifnot isinstance(score, (int, float)):raise TypeError("分数必须是数字")ifnot0 <= score <= 100:raise ValueError("分数必须在 0-100 之间")if name in self.scores:raise ValueError(f"{name} 的成绩已存在")        self.scores[name] = score        print(f"添加成功:{name}{score}分")defget(self, name):if name notin self.scores:raise KeyError(f"找不到学生:{name}")return self.scores[name]defreport(self):ifnot self.scores:raise ValueError("还没有成绩数据")        avg = sum(self.scores.values()) / len(self.scores)        print(f"人数:{len(self.scores)}")        print(f"平均:{avg:.1f}")        print(f"最高:{max(self.scores.values())}")        print(f"最低:{min(self.scores.values())}")# 使用manager = ScoreManager()whileTrue:try:        name = input("姓名(q退出):")if name.lower() == "q":break        score = float(input("分数:"))        manager.add(name, score)except (TypeError, ValueError) as e:        print(f"输入错误:{e}")except KeyError as e:        print(f"错误:{e}")try:    manager.report()except ValueError as e:    print(e)

最后

异常处理不是让你的代码"不报错",而是让你的代码"出错了也能优雅地应对"。

记住三件事:

  1. 只捕获你预期会发生的异常,别用空的 except: pass
  2. 用 raise 主动抛出异常,让调用者知道出了什么问题
  3. finally 用于资源清理,但 with 更好

我的建议:

把你写过的代码拿出来,找到那些直接使用用户输入或读取文件的地方。给它们加上 try-except,让程序在出错时给出友好的提示,而不是崩溃退出。

好的代码不是不出错,而是出了错也能从容应对。

今天就到这里。

我是陈默,我们下期再见。


如果你觉得这篇文章有帮助,欢迎关注我。我会持续分享 Python 学习的干货。

最新文章

随机文章