Skip to content

Python vs. JavaScript: 异常与错误处理对比指南

健壮的错误处理是构建可靠、可维护应用程序的生命线。本文档将深入对比 Python 和 JavaScript 在处理异常和错误时的核心哲学、语法结构和常见模式。

参考资料:


核心哲学与概念对比

  • Python: EAFP - "Easier to Ask for Forgiveness than Permission" 这是 Python 社区广泛推崇的编码风格,意为"请求原谅比获得许可更容易"。它鼓励开发者编写直接执行操作的代码,并使用 try...except 块来捕获和处理可能发生的异常。这被认为比在使用前进行大量检查(LBYL - "Look Before You Leap")更高效、更具可读性。

  • JavaScript: 多模式演进 JavaScript 的错误处理经历了从传统 try...catch,到 Node.js "错误优先回调",再到现代基于 Promise 的异步错误处理的演进。现代 JS 错误处理的核心是 Promise.catch() 和与 async/await 结合的 try...catch

特性 (Feature)PythonJavaScript
捕获块try...excepttry...catch
特定错误except ValueError as e:catch (e) { if (e instanceof TypeError) ... }
"成功"代码块else: (仅在 try 无异常时执行)无直接对应物
清理代码块finally:finally: (功能和语法相同)
抛出错误raise ValueError("信息")throw new Error("信息")
异步错误处理try...except 配合 awaitPromise.catch()try...catch 配合 await

1. 基本的错误捕获

Python: try...except

Python 的 except 块可以非常精确地捕获特定类型的异常。

python
def safe_divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("错误:不能除以零!")
        return None
    except TypeError as e:
        print(f"错误:参数类型不正确 - {e}")
        return None
    # 捕获所有其他类型的异常
    except Exception as e:
        print(f"发生未知错误: {e}")
        return None
    
    return result

JavaScript: try...catch

JS 的 catch (e) 会捕获 try 块中抛出的任何类型的错误。需要在 catch 块内部通过 instanceof 来判断具体错误类型。

javascript
function safeDivide(a, b) {
  try {
    if (b === 0) {
      // JS 不会自动抛出除零错误,需要手动检查
      throw new Error("不能除以零!");
    }
    if (typeof a !== 'number' || typeof b !== 'number') {
      throw new TypeError("参数必须是数字。");
    }
    return a / b;
  } catch (e) {
    if (e instanceof TypeError) {
      console.error(`类型错误: ${e.message}`);
    } else {
      console.error(`发生错误: ${e.message}`);
    }
    return null;
  }
}

2. 保证执行的清理工作: finally

finally 块确保无论是否发生异常,某些代码(如资源释放)都一定会被执行。两种语言的语法和功能几乎完全相同。

Python

python
f = None
try:
    f = open("my_file.txt", "r")
    # ... process file ...
finally:
    if f:
        f.close()
        print("文件已关闭。")
# 注:使用 'with open(...)' 是更 Pythonic 的方式,它自动处理了 finally 的逻辑。

JavaScript

javascript
let resource;
try {
  resource = acquireResource();
  // ... use resource ...
} finally {
  if (resource) {
    resource.release();
    console.log("资源已释放。");
  }
}

3. 成功时的逻辑: else (Python 独有)

Python 的 try...except 结构可以带一个 else 子句,它仅在 try 块没有抛出任何异常的情况下执行。这有助于将"可能出错的代码"与"成功后才应执行的代码"分离开,提升代码清晰度。

python
try:
    # 可能会失败的操作
    value = my_dict["key"] 
except KeyError:
    print("键不存在!")
else:
    # 只有在 try 成功后才执行
    print(f"成功获取值: {value}")

JavaScript 没有与此直接对应的语法。成功路径的代码会直接跟在 try 块中可能出错的代码之后。


4. 手动抛出错误: raise vs. throw

Python

使用 raise 关键字,通常后跟一个异常类的实例。

python
class MyCustomError(Exception):
    """一个自定义异常。"""
    pass

def check_age(age):
    if age < 18:
        raise MyCustomError("用户必须年满18岁。")
    return "验证通过"

JavaScript

使用 throw 关键字,通常后跟一个 Error 或其子类的实例。

javascript
class MyCustomError extends Error {
  constructor(message) {
    super(message);
    this.name = "MyCustomError";
  }
}

function checkAge(age) {
  if (age < 18) {
    throw new MyCustomError("用户必须年满18岁。");
  }
  return "验证通过";
}

5. 异步编程中的错误处理

Python (asyncio)

async/await 语法与 try...except 无缝集成,处理异步异常就像处理同步异常一样直观。

python
import asyncio

async def fetch_data(url):
    # ... 可能会抛出网络异常 ...
    print(f"正在获取 {url}")
    await asyncio.sleep(1) # 模拟网络请求
    if "error" in url:
        raise ConnectionError("无法连接到服务器")
    return {"data": "一些数据"}

async def main():
    try:
        data = await fetch_data("http://example.com")
        print("成功:", data)
    except ConnectionError as e:
        print(f"捕获到异步错误: {e}")

asyncio.run(main())

JavaScript (Promises & Async/Await)

Promise 链: 使用 .catch() 方法来捕获链上任何环节发生的错误。

javascript
fetch('http://example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP 错误! 状态: ${response.status}`);
    }
    return response.json();
  })
  .then(data => console.log(data))
  .catch(error => {
    console.error('Fetch 操作失败:', error);
  });

Async/Await: 这是现代 JS 中处理异步错误的首选方式,它让代码回归 try...catch 的直观结构。

javascript
async function fetchData(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`HTTP 错误! 状态: ${response.status}`);
    }
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('Fetch 操作失败:', error);
  }
}

</rewritten_file>