Python异常处理基础

本教程将介绍Python异常处理的基础知识,包括异常的概念、常见异常类型、try-except语句的使用等。通过本教程,你将学会如何优雅地处理程序中可能出现的错误。

异常简介

异常是程序运行时出现的错误。在Python中,当出现错误时,程序会创建一个异常对象。如果异常没有被处理,程序将会终止并显示一个错误信息。

异常示例


# 常见的异常情况
print(10 / 0)  # ZeroDivisionError: division by zero

name = "Python"
print(name[10])  # IndexError: string index out of range

number = int("abc")  # ValueError: invalid literal for int() with base 10: 'abc'

import nonexistent_module  # ModuleNotFoundError: No module named 'nonexistent_module'
                    

常见异常类型

Python内置了许多异常类型,以下是一些常见的异常:

内置异常

  • SyntaxError: 语法错误
  • NameError: 使用未定义的变量
  • TypeError: 类型错误
  • ValueError: 值错误
  • IndexError: 索引超出范围
  • KeyError: 字典中不存在的键
  • FileNotFoundError: 文件不存在
  • ZeroDivisionError: 除以零
  • AttributeError: 访问不存在的属性
  • ImportError: 导入模块失败

异常层次结构


BaseException
 ├── SystemExit
 ├── KeyboardInterrupt
 ├── GeneratorExit
 └── Exception
      ├── StopIteration
      ├── ArithmeticError
      │    ├── FloatingPointError
      │    ├── OverflowError
      │    └── ZeroDivisionError
      ├── AssertionError
      ├── AttributeError
      ├── BufferError
      ├── EOFError
      ├── ImportError
      │    └── ModuleNotFoundError
      ├── LookupError
      │    ├── IndexError
      │    └── KeyError
      ├── MemoryError
      ├── NameError
      ├── OSError
      │    ├── FileNotFoundError
      │    ├── PermissionError
      │    └── TimeoutError
      ├── RuntimeError
      ├── SyntaxError
      ├── TypeError
      └── ValueError
                    

try-except语句

try-except语句用于捕获和处理异常。try块中放置可能产生异常的代码,except块中放置处理异常的代码。

基本语法


# 基本的try-except结构
try:
    # 可能产生异常的代码
    number = int(input("请输入一个数字:"))
    result = 100 / number
    print(f"100除以{number}等于{result}")
except ValueError:
    print("输入无效,请输入一个数字")
except ZeroDivisionError:
    print("除数不能为零")
except:  # 捕获所有其他异常
    print("发生了其他错误")

# 使用as关键字获取异常对象
try:
    with open("nonexistent.txt") as f:
        content = f.read()
except FileNotFoundError as e:
    print(f"错误信息:{e}")
    print(f"错误类型:{type(e).__name__}")
                    

多个异常处理


def safe_convert_to_number(value):
    """安全地将输入转换为数字"""
    try:
        # 尝试转换为整数
        return int(value)
    except ValueError:
        try:
            # 如果转换整数失败,尝试转换为浮点数
            return float(value)
        except ValueError:
            # 如果都失败了,返回None
            return None

# 使用示例
inputs = ["123", "45.67", "abc", "0", "12.0"]
for value in inputs:
    result = safe_convert_to_number(value)
    if result is None:
        print(f"无法将 '{value}' 转换为数字")
    else:
        print(f"转换结果:{result}")
                    

finally子句

finally子句中的代码无论是否发生异常都会执行,通常用于清理资源。

使用finally


def read_file_safely(filename):
    """安全地读取文件内容"""
    f = None
    try:
        f = open(filename, 'r', encoding='utf-8')
        return f.read()
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return None
    except Exception as e:
        print(f"读取文件时发生错误:{e}")
        return None
    finally:
        if f is not None:
            f.close()
            print("文件已关闭")

# 使用with语句(推荐)
def read_file_with_with(filename):
    """使用with语句读取文件"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return f.read()
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return None
    except Exception as e:
        print(f"读取文件时发生错误:{e}")
        return None
                    

抛出异常

使用raise语句可以主动抛出异常。当程序出现不符合要求的情况时,可以抛出异常来提醒调用者。

使用raise


def divide(a, b):
    """除法函数"""
    if not isinstance(a, (int, float)) or not isinstance(b, (int, float)):
        raise TypeError("参数必须是数字")
    if b == 0:
        raise ValueError("除数不能为零")
    return a / b

def calculate_square_root(number):
    """计算平方根"""
    if number < 0:
        raise ValueError("不能计算负数的平方根")
    return number ** 0.5

# 使用示例
try:
    result = divide(10, "2")
except TypeError as e:
    print(f"类型错误:{e}")

try:
    result = calculate_square_root(-4)
except ValueError as e:
    print(f"值错误:{e}")
                    

实践练习

以下是一些练习题,帮助你更好地理解异常处理:

练习1:安全的列表访问


def safe_get_element(lst, index, default=None):
    """安全地获取列表元素"""
    try:
        return lst[index]
    except IndexError:
        return default

# 测试代码
numbers = [1, 2, 3, 4, 5]
print(safe_get_element(numbers, 1))    # 输出: 2
print(safe_get_element(numbers, 10))   # 输出: None
print(safe_get_element(numbers, -1))   # 输出: 5
print(safe_get_element(numbers, 3, 0)) # 输出: 4
                    

练习2:用户输入验证


def get_valid_age():
    """获取有效的年龄输入"""
    while True:
        try:
            age = int(input("请输入你的年龄:"))
            if age < 0 or age > 150:
                raise ValueError("年龄必须在0到150之间")
            return age
        except ValueError as e:
            if str(e).startswith("年龄必须在"):
                print(e)
            else:
                print("请输入有效的数字")
        except KeyboardInterrupt:
            print("\n程序已取消")
            return None

# 使用示例
age = get_valid_age()
if age is not None:
    print(f"你的年龄是:{age}")
                    

练习3:文件处理


def process_file(filename):
    """处理文件内容"""
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            lines = f.readlines()
            
        # 处理每一行
        numbers = []
        for i, line in enumerate(lines, 1):
            try:
                number = float(line.strip())
                numbers.append(number)
            except ValueError:
                print(f"第{i}行不是有效的数字:{line.strip()}")
        
        # 计算统计信息
        if numbers:
            average = sum(numbers) / len(numbers)
            maximum = max(numbers)
            minimum = min(numbers)
            return {
                'count': len(numbers),
                'average': average,
                'max': maximum,
                'min': minimum
            }
        return None
        
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
    except Exception as e:
        print(f"处理文件时发生错误:{e}")
    
    return None

# 使用示例
result = process_file('numbers.txt')
if result:
    print("文件统计信息:")
    print(f"数字个数:{result['count']}")
    print(f"平均值:{result['average']:.2f}")
    print(f"最大值:{result['max']}")
    print(f"最小值:{result['min']}")