Skip to content

异常处理

try-except 语句

Python 异常处理

基本异常处理

python
# Python - 基本异常处理
def divide_numbers(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("错误:除数不能为零")
        return None
    except TypeError:
        print("错误:参数类型不正确")
        return None

# 测试异常处理
print(divide_numbers(10, 2))   # 5.0
print(divide_numbers(10, 0))   # 错误:除数不能为零
print(divide_numbers("10", 2)) # 错误:参数类型不正确

# 多个异常类型
def process_data(data):
    try:
        if isinstance(data, str):
            return int(data)
        elif isinstance(data, (int, float)):
            return data
        else:
            raise ValueError("不支持的数据类型")
    except (ValueError, TypeError) as e:
        print(f"数据处理错误: {e}")
        return None

# 测试多种异常
print(process_data("123"))     # 123
print(process_data(456))       # 456
print(process_data("abc"))     # 数据处理错误: invalid literal for int() with base 10: 'abc'
print(process_data([1, 2, 3])) # 数据处理错误: 不支持的数据类型

完整的异常处理结构

python
# Python - 完整的异常处理结构
def file_operations(filename):
    try:
        # 尝试打开文件
        with open(filename, 'r', encoding='utf-8') as f:
            content = f.read()
            print("文件读取成功")
            return content
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return None
    except PermissionError:
        print(f"没有权限读取文件 {filename}")
        return None
    except UnicodeDecodeError:
        print(f"文件 {filename} 编码错误")
        return None
    except Exception as e:
        print(f"未知错误: {e}")
        return None
    else:
        # 只有在没有异常时执行
        print("文件操作完成")
    finally:
        # 无论是否有异常都会执行
        print("清理资源")

# 测试文件操作
file_operations("nonexistent.txt")
file_operations("example.txt")

异常链和重新抛出

python
# Python - 异常链和重新抛出
def low_level_function():
    try:
        result = 10 / 0
    except ZeroDivisionError as e:
        raise RuntimeError("低级函数出错") from e

def high_level_function():
    try:
        low_level_function()
    except RuntimeError as e:
        print(f"高级函数捕获到错误: {e}")
        print(f"原始错误: {e.__cause__}")

# 测试异常链
high_level_function()

# 重新抛出异常
def process_user_input(user_input):
    try:
        age = int(user_input)
        if age < 0 or age > 150:
            raise ValueError("年龄必须在 0-150 之间")
        return age
    except ValueError as e:
        print(f"输入验证失败: {e}")
        raise  # 重新抛出异常

# 测试重新抛出
try:
    age = process_user_input("abc")
except ValueError:
    print("程序无法处理无效输入")

JavaScript 异常处理

基本异常处理

javascript
// JavaScript - 基本异常处理
function divideNumbers(a, b) {
  try {
    const result = a / b;
    if (!isFinite(result)) {
      throw new Error("计算结果无效");
    }
    return result;
  } catch (error) {
    if (error.message === "计算结果无效") {
      console.log("错误:除数不能为零");
    } else {
      console.log("错误:参数类型不正确");
    }
    return null;
  }
}

// 测试异常处理
console.log(divideNumbers(10, 2)); // 5
console.log(divideNumbers(10, 0)); // 错误:除数不能为零
console.log(divideNumbers("10", 2)); // 错误:参数类型不正确

// 多个异常类型
function processData(data) {
  try {
    if (typeof data === "string") {
      const result = parseInt(data);
      if (isNaN(result)) {
        throw new Error("无法转换为数字");
      }
      return result;
    } else if (typeof data === "number") {
      return data;
    } else {
      throw new Error("不支持的数据类型");
    }
  } catch (error) {
    console.log(`数据处理错误: ${error.message}`);
    return null;
  }
}

// 测试多种异常
console.log(processData("123")); // 123
console.log(processData(456)); // 456
console.log(processData("abc")); // 数据处理错误: 无法转换为数字
console.log(processData([1, 2, 3])); // 数据处理错误: 不支持的数据类型

完整的异常处理结构

javascript
// JavaScript - 完整的异常处理结构
async function fileOperations(filename) {
  let fileHandle = null;

  try {
    // 尝试打开文件
    fileHandle = await fs.open(filename, "r");
    const content = await fileHandle.readFile("utf-8");
    console.log("文件读取成功");
    return content;
  } catch (error) {
    if (error.code === "ENOENT") {
      console.log(`文件 ${filename} 不存在`);
    } else if (error.code === "EACCES") {
      console.log(`没有权限读取文件 ${filename}`);
    } else {
      console.log(`未知错误: ${error.message}`);
    }
    return null;
  } finally {
    // 无论是否有异常都会执行
    if (fileHandle) {
      await fileHandle.close();
    }
    console.log("清理资源");
  }
}

// 测试文件操作
fileOperations("nonexistent.txt");
fileOperations("example.txt");

异常链和重新抛出

javascript
// JavaScript - 异常链和重新抛出
function lowLevelFunction() {
  try {
    const result = 10 / 0;
    return result;
  } catch (error) {
    throw new Error("低级函数出错", { cause: error });
  }
}

function highLevelFunction() {
  try {
    lowLevelFunction();
  } catch (error) {
    console.log(`高级函数捕获到错误: ${error.message}`);
    console.log(`原始错误: ${error.cause}`);
  }
}

// 测试异常链
highLevelFunction();

// 重新抛出异常
function processUserInput(userInput) {
  try {
    const age = parseInt(userInput);
    if (isNaN(age) || age < 0 || age > 150) {
      throw new Error("年龄必须在 0-150 之间");
    }
    return age;
  } catch (error) {
    console.log(`输入验证失败: ${error.message}`);
    throw error; // 重新抛出异常
  }
}

// 测试重新抛出
try {
  const age = processUserInput("abc");
} catch (error) {
  console.log("程序无法处理无效输入");
}

自定义异常

Python 自定义异常

python
# Python - 自定义异常类
class ValidationError(Exception):
    """验证错误异常"""
    def __init__(self, message, field=None):
        self.message = message
        self.field = field
        super().__init__(self.message)

class DatabaseError(Exception):
    """数据库错误异常"""
    def __init__(self, message, error_code=None):
        self.message = message
        self.error_code = error_code
        super().__init__(self.message)

# 使用自定义异常
def validate_user_data(data):
    """验证用户数据"""
    if not isinstance(data, dict):
        raise ValidationError("数据必须是字典类型")

    if 'name' not in data:
        raise ValidationError("缺少姓名字段", field='name')

    if 'age' not in data:
        raise ValidationError("缺少年龄字段", field='age')

    if not isinstance(data['age'], int) or data['age'] < 0:
        raise ValidationError("年龄必须是正整数", field='age')

    return True

# 测试自定义异常
try:
    validate_user_data({"name": "Alice"})
except ValidationError as e:
    print(f"验证错误: {e.message}, 字段: {e.field}")

try:
    validate_user_data({"name": "Bob", "age": -5})
except ValidationError as e:
    print(f"验证错误: {e.message}, 字段: {e.field}")

JavaScript 自定义异常

javascript
// JavaScript - 自定义异常类
class ValidationError extends Error {
  constructor(message, field = null) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

class DatabaseError extends Error {
  constructor(message, errorCode = null) {
    super(message);
    this.name = "DatabaseError";
    this.errorCode = errorCode;
  }
}

// 使用自定义异常
function validateUserData(data) {
  if (typeof data !== "object" || data === null) {
    throw new ValidationError("数据必须是对象类型");
  }

  if (!data.hasOwnProperty("name")) {
    throw new ValidationError("缺少姓名字段", "name");
  }

  if (!data.hasOwnProperty("age")) {
    throw new ValidationError("缺少年龄字段", "age");
  }

  if (typeof data.age !== "number" || data.age < 0) {
    throw new ValidationError("年龄必须是正整数", "age");
  }

  return true;
}

// 测试自定义异常
try {
  validateUserData({ name: "Alice" });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(`验证错误: ${error.message}, 字段: ${error.field}`);
  }
}

try {
  validateUserData({ name: "Bob", age: -5 });
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(`验证错误: ${error.message}, 字段: ${error.field}`);
  }
}

异常处理最佳实践

Python 最佳实践

python
# Python - 异常处理最佳实践
import logging

# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class DataProcessor:
    def __init__(self):
        self.processed_count = 0
        self.error_count = 0

    def process_item(self, item):
        """处理单个数据项"""
        try:
            # 验证数据
            if not self._validate_item(item):
                raise ValueError("数据验证失败")

            # 处理数据
            result = self._transform_item(item)

            # 记录成功
            self.processed_count += 1
            logger.info(f"成功处理项目: {item}")

            return result

        except ValueError as e:
            # 处理已知错误
            self.error_count += 1
            logger.warning(f"数据验证错误: {e}")
            return None

        except Exception as e:
            # 处理未知错误
            self.error_count += 1
            logger.error(f"处理项目时发生未知错误: {e}", exc_info=True)
            return None

    def _validate_item(self, item):
        """验证数据项"""
        return isinstance(item, (int, float, str)) and item is not None

    def _transform_item(self, item):
        """转换数据项"""
        if isinstance(item, str):
            return item.upper()
        elif isinstance(item, (int, float)):
            return item * 2
        else:
            raise ValueError("不支持的数据类型")

    def get_statistics(self):
        """获取处理统计"""
        return {
            'processed': self.processed_count,
            'errors': self.error_count,
            'success_rate': self.processed_count / (self.processed_count + self.error_count) if (self.processed_count + self.error_count) > 0 else 0
        }

# 使用最佳实践
processor = DataProcessor()
items = [1, "hello", None, 3.14, "world"]

for item in items:
    result = processor.process_item(item)

stats = processor.get_statistics()
print(f"处理统计: {stats}")

JavaScript 最佳实践

javascript
// JavaScript - 异常处理最佳实践
class DataProcessor {
  constructor() {
    this.processedCount = 0;
    this.errorCount = 0;
  }

  processItem(item) {
    try {
      // 验证数据
      if (!this._validateItem(item)) {
        throw new Error("数据验证失败");
      }

      // 处理数据
      const result = this._transformItem(item);

      // 记录成功
      this.processedCount++;
      console.log(`成功处理项目: ${item}`);

      return result;
    } catch (error) {
      // 处理错误
      this.errorCount++;

      if (error.message === "数据验证失败") {
        console.warn(`数据验证错误: ${error.message}`);
      } else {
        console.error(`处理项目时发生未知错误: ${error.message}`);
        console.error(error.stack);
      }

      return null;
    }
  }

  _validateItem(item) {
    return (
      item !== null &&
      item !== undefined &&
      (typeof item === "string" || typeof item === "number")
    );
  }

  _transformItem(item) {
    if (typeof item === "string") {
      return item.toUpperCase();
    } else if (typeof item === "number") {
      return item * 2;
    } else {
      throw new Error("不支持的数据类型");
    }
  }

  getStatistics() {
    const total = this.processedCount + this.errorCount;
    return {
      processed: this.processedCount,
      errors: this.errorCount,
      successRate: total > 0 ? this.processedCount / total : 0,
    };
  }
}

// 使用最佳实践
const processor = new DataProcessor();
const items = [1, "hello", null, 3.14, "world"];

items.forEach((item) => {
  processor.processItem(item);
});

const stats = processor.getStatistics();
console.log(`处理统计:`, stats);

异常处理对比

特性PythonJavaScript
基本语法try/excepttry/catch
异常类型ExceptionError
多个异常except (Type1, Type2):多个 catch
异常信息except Exception as e:catch (error) {}
清理代码finallyfinally
重新抛出raisethrow
异常链raise NewError() from ethrow new Error("msg", {cause: e})

练习

  1. 创建一个文件读取函数,处理各种可能的异常

参考答案:

python
# Python
def read_file(filename):
    try:
        with open(filename, 'r', encoding='utf-8') as f:
            return f.read()
    except FileNotFoundError:
        print('文件未找到')
    except PermissionError:
        print('没有权限')
    except Exception as e:
        print('其他错误:', e)
javascript
// JavaScript (Node.js)
const fs = require("fs");
function readFile(filename) {
  try {
    return fs.readFileSync(filename, "utf-8");
  } catch (err) {
    if (err.code === "ENOENT") {
      console.log("文件未找到");
    } else if (err.code === "EACCES") {
      console.log("没有权限");
    } else {
      console.log("其他错误:", err);
    }
  }
}
  1. 实现一个数据验证类,使用自定义异常

参考答案:

python
# Python
class ValidationError(Exception):
    pass
class Validator:
    def validate_age(self, age):
        if not (0 <= age <= 120):
            raise ValidationError("年龄不合法")
try:
    Validator().validate_age(150)
except ValidationError as e:
    print(e)
javascript
// JavaScript
class ValidationError extends Error {}
class Validator {
  validateAge(age) {
    if (age < 0 || age > 120) {
      throw new ValidationError("年龄不合法");
    }
  }
}
try {
  new Validator().validateAge(150);
} catch (e) {
  console.log(e.message);
}
  1. 创建一个网络请求函数,处理连接超时和错误

参考答案:

python
# Python
import requests
try:
    response = requests.get("https://httpbin.org/delay/3", timeout=1)
except requests.Timeout:
    print("请求超时")
except requests.RequestException as e:
    print("请求错误:", e)
javascript
// JavaScript (Node.js)
const axios = require("axios");
axios
  .get("https://httpbin.org/delay/3", { timeout: 1000 })
  .then((res) => console.log(res.status))
  .catch((err) => {
    if (err.code === "ECONNABORTED") {
      console.log("请求超时");
    } else {
      console.log("请求错误:", err.message);
    }
  });
  1. 实现一个计算器类,处理除零和类型错误

参考答案:

python
# Python
class Calculator:
    def divide(self, a, b):
        try:
            return a / b
        except ZeroDivisionError:
            print("除数不能为零")
        except TypeError:
            print("类型错误")
calc = Calculator()
calc.divide(10, 0)
calc.divide(10, "a")
javascript
// JavaScript
class Calculator {
  divide(a, b) {
    try {
      if (typeof a !== "number" || typeof b !== "number") {
        throw new TypeError("类型错误");
      }
      if (b === 0) {
        throw new Error("除数不能为零");
      }
      return a / b;
    } catch (e) {
      console.log(e.message);
    }
  }
}
const calc = new Calculator();
calc.divide(10, 0);
calc.divide(10, "a");
  1. 比较 Python 和 JavaScript 的异常处理机制差异

参考答案:

  • Python 使用 try/except/finally,支持自定义异常类,异常类型丰富。
  • JavaScript 使用 try/catch/finally,异常为 Error 派生类,类型较少。
  • Python 支持多 except 分支,JS 只能用 if 判断 error 类型。

下一步

现在你已经了解了异常处理,接下来我们将学习项目依赖管理。