You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免JSON返回NoneType导致Python代码报错并提升鲁棒性

问题:Python处理REST API返回JSON的空值异常优化

场景与问题

通过REST API获取如下JSON格式数据:

{
  "itineraryIntent": {
    "itineraryId": 2446,
    "userNodes": [
      {
        "user": {
          "id": "-2",
          "givenName": "Wiliam Never",
          "preferredAirport": "",
          "travelerGroupId": null,
          "externalId": null,
          "externalId2": null,
          "checkCCFieldForTraveler": false,
          "notificationEmailOverride": null,
          "paxType": 0,
          "title": "Dr",
          "middleName": null,
          "dateOfBirth": "1980-01-15T00:00:00Z",
          "phoneNumber": null,
          "tsaInfo": null,
          "source": "RequestEndPoint",
          "allowBookingGuestTraveler": null,
          "gdsTravelerProfileContainsFirstName": false,
          "profilesFound": {
            "Agency": null,
            "Corporate": null,
            "Traveler": null
          },
          "userId": "-2",
          "firstName": "Wiliam",
          "lastName": "Never"
        },
        "elements": []
      }
    ]
  }
}

原提取代码如下,80%场景可用,但偶尔因details["itineraryIntent"]["userNodes"]为null,抛出TypeError: 'NoneType' object is not subscriptable异常:

details = response.json()
checkIntent = details["itineraryIntent"]["userNodes"][0]["elements"]

if len(checkIntent) == 0:
  print("No intent found, nothing is classified")
  return False
else:
  return True

此前采用固定sleep 10秒的临时方案,但多数场景仅需4-5秒即可获取有效响应,需优化代码实现鲁棒性,无需依赖固定sleep。

优化方案

核心思路

  1. 安全取值:避免直接下标访问,用dict.get()逐层获取字段并设置默认值,防止空值或不存在的键引发异常
  2. 智能重试:替代固定sleep,采用递增延迟的重试策略,适配不同场景的响应速度
  3. 全面异常捕获:覆盖网络请求、JSON解析等多种异常,避免程序崩溃

优化后代码

import time
import requests

def check_itinerary_intent(response):
    # 逐层安全获取字段,设置默认值避免空值异常
    itinerary_intent = response.json().get("itineraryIntent", {})
    user_nodes = itinerary_intent.get("userNodes", [])
    
    # 校验userNodes是否有效
    if not user_nodes:
        return False
    
    # 安全获取第一个节点的elements
    elements = user_nodes[0].get("elements", [])
    if len(elements) == 0:
        print("No intent found, nothing is classified")
        return False
    return True

def fetch_and_check_intent(api_url, max_retries=3, initial_delay=4):
    retries = 0
    while retries < max_retries:
        try:
            # 发送请求并校验HTTP状态码
            response = requests.get(api_url)
            response.raise_for_status()
            
            # 检查intent是否有效
            intent_result = check_itinerary_intent(response)
            if intent_result:
                return True
            # 若intent为空但userNodes有效,直接返回结果
            return False
        except (requests.exceptions.RequestException, ValueError) as e:
            print(f"处理错误: {str(e)}")
        
        # 仅当userNodes为空时重试,采用递增延迟
        retries += 1
        delay = initial_delay + (retries - 1)
        print(f"userNodes未就绪,{delay}秒后重试(第{retries}/{max_retries}次)")
        time.sleep(delay)
    
    print("重试次数耗尽,未获取有效数据")
    return False

优化点说明

  • 安全取值:用dict.get()替代直接下标访问,对每个层级的字段设置默认值(空字典/空列表),彻底避免None下标访问异常和KeyError
  • 智能重试:采用递增延迟策略(首次4秒,后续每次加1秒),既适配多数场景的快速响应,也给少数需要更长等待的请求留出时间,替代低效的固定10秒sleep
  • 职责拆分:将数据校验和请求重试逻辑拆分,代码更清晰易维护
  • 异常覆盖:捕获网络请求错误(如连接超时、HTTP错误)和JSON解析错误,确保程序稳定运行

内容的提问来源于stack exchange,提问作者Rustom Contractor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 14:13:13