【问题标题】:How to avoid KeyError from missing dict keys?如何避免 KeyError 丢失字典键?
【发布时间】:2021-01-28 02:12:13
【问题描述】:

我正在运行一个循环发出 GET 请求的脚本。我测试一个成功的响应,然后将响应转换为一个 json 对象并做一些事情。我的代码如下所示:

response = requests.get(url=url)
if response.status_code == 200:
    response_json = response.json()
    <do stuff>
else:
    <handle error>

有时我得到一个成功的响应,但无论出于何种原因,dict 会返回一些丢失的数据,并且我的脚本会从 KeyError 中断。我想进行防弹测试以避免错误并检索response_json['Data']['Data'][1]'high''low' 的值。 dict的结构是:

{'Data': {'Aggregated': False,
          'Data': [{'close': 0.8062,
                    'conversionType': 'multiply',
                    'high': 0.8084,
                    'low': 0.788,
                    'open': 0.8102,
                    'time': 1428465600,
                    'volumefrom': 145.38,
                    'volumeto': 117.2},
                   {'close': 0.8,
                    'conversionType': 'multiply',
                    'high': 0.8101,
                    'low': 0.8,
                    'open': 0.8062,
                    'time': 1428469200,
                    'volumefrom': 262.39,
                    'volumeto': 209.92}],
          'TimeFrom': 1428465600,
          'TimeTo': 1428469200},
 'HasWarning': False,
 'Message': '',
 'RateLimit': {},
 'Response': 'Success',
 'Type': 100}

我目前最好的测试尝试是:

if 'Data' in response_json:
    if 'Data' in 'Data':
        if len(response_json['Data']['Data']) > 1:
            if 'low' and 'high' in response_json['Data']['Data'][1]:
                if 'low' != None and 'high' != None:
                    <do stuff>    
else:
    print("Error:", url)

我相信这涵盖了所有基础,但它看起来很笨拙。有没有更好的方法来测试在这种情况下是否存在键和有效值,和/或保持我的脚本运行而不会中断?

还想知道在每个嵌套条件测试之后是否需要一个else 语句,或者如果其中一个条件返回False,Python 是否会默认使用底部的else

【问题讨论】:

  • if 'Data' in 'Data': 总是正确的 - 这是一个无操作
  • if 'low' and 'high' in response_json['Data']['Data'][1] 这也总是正确的——出于不同的原因:stackoverflow.com/questions/6159313/…
  • 如果'Data' in 'Data':,你怎么能确定它总是正确的?
  • if 'low' != None and 'high' != None: 这也总是正确的——显然
  • 另外,if 'low' and 'high' in response_json['Data']['Data'][1]: 根本没有测试'low' 的存在,原因大致相同,它不起作用here

标签: python dictionary conditional-statements keyerror


【解决方案1】:

字典支持[] operatorget(k) 方法。如您所知,[] operator 在找不到密钥 k 时会抛出 KeyError,而 get(k) 只会返回 None

d = {'a':1, 'b': 2, 'c':3}
print(str.format("c: '{}'", d.get('c')))    # c: '3'
print(str.format("d: '{}'", d.get('d')))    # d: 'None'

由于@sleepyhead也是cmets,你也可以提供一个带key的默认返回值,比如:

print(str.format("d: '{}'", d.get('d', -1))) # d: '-1'

当然,这只有在您可以提供与有效返回值域不相关的默认返回值时才有用。

【讨论】:

  • 你也可以提供一个得到的默认值,比如d.get('d', 'something')
【解决方案2】:

您可以使用 try-except 块来确保脚本即使遇到错误也能继续运行。

例如,您可以像这样构造它:

response = requests.get(url=url)
if response.status_code == 200:
    response_json = response.json()
    try:
        <stuff>
    except KeyError:
        <handle error> #or you can just pass the faulty data
else:
    <handle error>

【讨论】:

    【解决方案3】:

    我找不到任何 XPath 类型的方法来查找 json 中的键,因此需要堆叠的 if 语句。

    您需要修正语法以获得正确的值。

    试试这个代码:

    response_json = {'Data': {'Aggregated': False,
              'Data': [{'close': 0.8062,
                        'conversionType': 'multiply',
                        'high': 0.8084,
                        'low': 0.788,
                        'open': 0.8102,
                        'time': 1428465600,
                        'volumefrom': 145.38,
                        'volumeto': 117.2},
                       {'close': 0.8,
                        'conversionType': 'multiply',
                        'high': 0.8101,
                        'low': 0.8,
                        'open': 0.8062,
                        'time': 1428469200,
                        'volumefrom': 262.39,
                        'volumeto': 209.92}],
              'TimeFrom': 1428465600,
              'TimeTo': 1428469200},
     'HasWarning': False,
     'Message': '',
     'RateLimit': {},
     'Response': 'Success',
     'Type': 100}
    
    
    low = high = None  # default values
    if 'Data' in response_json.keys():
        if 'Data' in response_json['Data'].keys():
            if len(response_json['Data']['Data']) > 1:
                if 'low' in response_json['Data']['Data'][1]:
                   if 'high' in response_json['Data']['Data'][1]:
                      if response_json['Data']['Data'][1]['low'] and response_json['Data']['Data'][1]['high']:
                            low  = response_json['Data']['Data'][1]['low']
                            high = response_json['Data']['Data'][1]['high']
    
    if low and high:   # actually only need to check one                      
       print('<do stuff>', 'low', response_json['Data']['Data'][1]['low'])
       print('<do stuff>', 'high', response_json['Data']['Data'][1]['high'])
    else:
       print("High\Low not found")
    

    【讨论】:

      猜你喜欢
      • 2014-09-08
      • 2018-02-11
      • 2018-08-11
      • 2017-10-19
      • 1970-01-01
      • 2018-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多