Timeout与TimeoutError的区别

# Python中Timeout与TimeoutError异常详解(含requests、Tushare实战)

在Python网络编程、接口调用(如Tushare、requests)及异步开发中,`Timeout`和`TimeoutError`是高频出现的超时异常。二者名称高度相似,但**本质与适用场景完全不同**,很多开发者容易混淆,进而导致异常捕获不全面、程序重试逻辑失效。本文将从所属模块、继承关系、触发场景等核心维度深度对比二者,结合requests接口测试、Tushare金融数据调用实战,给出可直接落地的代码示例与避坑指南。

一、核心区别一览表

|对比项|`Timeout`|`TimeoutError`

所属模块`requests.exceptions`(第三方库专属,仅requests可用)Python内置异常`builtins`(系统通用,无需额外导入)

继承关系`RequestException` → `OError` → `Exception``OSError` → `Exception`

触发场景HTTP请求层面,等待服务器响应超时,系统级操作层面,如socket、异步协程、锁等待等超时

典型用法`requests.get(url, timeout=5)`超时后抛出`asyncio.wait_for()`、`socket.settimeout()`超时后抛出

 二、`Timeout`异常(requests库专属)

1. 异常定义

`Timeout`是requests网络请求库自定义的异常类,完整路径为`requests.exceptions.Timeout`,仅作用于requests发起的HTTP/HTTPS请求,不属于Python内置异常,使用前需手动导入。

2. 触发条件

当使用requests发送HTTP/HTTPS请求时,通过`timeout`参数指定等待服务器响应的最长时间(单位:秒),若超过该时间仍未收到服务器的响应(包括连接建立超时、数据返回超时),则直接抛出该异常,仅影响HTTP请求流程,不涉及系统级操作。

3. 代码示例(结合文档接口实战)

以下示例调用文档中延迟5秒响应的接口(`https://httpbin.org/delay/5`),设置超时时间为2秒,模拟requests请求超时场景:

"""

 python

import requests

from requests.exceptions import Timeout

def test_request_timeout():

    try:

        # 目标接口延迟5秒响应,设置超时2秒(小于响应延迟,必然触发超时)

        resp = requests.get("https://httpbin.org/delay/5", timeout=2)

        resp.raise_for_status()  # 若未超时,校验HTTP状态码

    except Timeout:

        print("requests请求超时!2秒内未获取到服务器响应")

if __name__ == "__main__":

    test_request_timeout()

"""

三、`TimeoutError`异常(Python内置通用)

1. 异常定义

`TimeoutError`是Python内置的标准异常,属于系统级通用超时异常,无需额外导入即可使用,继承自`OSError`,适用于所有系统级阻塞操作的超时场景。

2. 触发场景

该异常不局限于网络请求,主要作用于系统级阻塞操作,常见场景包括:

- 套接字(socket)操作:设置超时后,连接、读取、写入等操作超时;

- 异步编程:`asyncio.wait_for()`等待协程执行超时;

- 线程/进程同步:`threading.Lock.acquire(timeout=)`等待锁超时;

- 其他系统I/O阻塞操作:如文件读写、管道通信等超时。

 3. 代码示例(异步任务超时)

以下示例模拟耗时10秒的异步任务,设置等待超时时间为3秒,触发`TimeoutError`异常:

"""

python

import asyncio

async def slow_task():

    # 模拟耗时10秒的异步任务(如复杂计算、系统调用)

    await asyncio.sleep(10)

async def test_async_timeout():

    try:

        # 等待协程执行,超时时间设为3秒(小于任务耗时,触发超时)

        await asyncio.wait_for(slow_task(), timeout=3)

    except TimeoutError:

        print("异步任务超时!3秒内未执行完成")

if __name__ == "__main__":

    asyncio.run(test_async_timeout())

"""

四、Tushare接口调用中的超时异常实战

Tushare是量化交易中常用的金融数据接口,其底层基于requests库发起HTTP请求,因此超时异常逻辑与requests高度相关,但需兼顾系统级超时场景,避免重试逻辑遗漏。

核心特点:

1. Tushare内部会封装底层socket异常,对外直接抛出的超时异常,大多为`requests.exceptions.Timeout`;

2. 若要保证重试逻辑覆盖所有超时场景,需同时捕获requests相关异常(含`Timeout`)和Python内置`TimeoutError`。

重试装饰器实战代码(可直接落地)

结合`tenacity`重试库,编写带重试机制的Tushare日线数据获取函数,兼容两种超时异常,提升接口调用稳定性:

"""

python

import tushare as ts

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type

from requests.exceptions import Timeout, RequestException  # 导入requests相关异常

# 初始化Tushare(请替换为自己的个人token,从Tushare官网获取)

ts.set_token("your_tushare_token")

pro = ts.pro_api()

@retry(

    stop=stop_after_attempt(3),  # 最大重试3次,避免无限重试

    wait=wait_exponential(multiplier=1, min=2, max=10),  # 指数退避:初始2秒,最大10秒,减轻接口压力

    retry=retry_if_exception_type((RequestException, TimeoutError))  # 捕获请求异常+两种超时异常

)

def get_daily_with_retry(ts_code, trade_date):

    """带重试机制的Tushare日线数据获取函数,适配超时异常"""

    # 调用Tushare日线接口,底层基于requests发起请求

    return pro.daily(ts_code=ts_code, trade_date=trade_date)

# 调用示例(获取平安银行2024年1月1日日线数据)

if __name__ == "__main__":

    try:

        data = get_daily_with_retry(ts_code="000001.SZ", trade_date="20240101")

        print("获取日线数据成功:")

        print(data)

    except (RequestException, TimeoutError):

        print("多次重试后仍超时,获取数据失败,请检查网络或接口状态")

   

"""

五、总结(核心避坑要点)

1. **`Timeout`** **:HTTP请求层专属** - 仅requests等网络库使用,对应HTTP请求等待服务器响应超时,需导入`requests.exceptions.Timeout`才能捕获;

2. **`TimeoutError`** **:系统层通用内置** - 不局限于网络请求,对应socket、异步、锁等待等系统级操作超时,无需导入即可直接捕获;

3. **Tushare开发避坑** - 优先捕获`requests.exceptions.RequestException`(该异常已包含`Timeout`),同时补充捕获`TimeoutError`,确保所有超时场景都能被覆盖,避免程序因未捕获异常而崩溃。

明确二者的区别后,可精准设计异常捕获逻辑,结合重试机制,大幅提升Python接口调用(尤其是网络请求、金融数据接口)的稳定性和健壮性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值