2009-10-12 9 views
3

У меня довольно сложный объект (десериализованный json, поэтому у меня нет слишком много контроля над ним), что мне нужно проверить существование и повторить по довольно глубоким элементам, так что прямо сейчас у меня есть что-то вроде этого:Есть ли более чистый способ цепочки пустых проверок в Python?

if a.get("key") and a["key"][0] and a["key"][0][0] : 
    for b in a["key"][0][0] : 
     #Do something 

который работает, но довольно уродлив. Кажется, что должен быть лучший способ сделать это, так что же более элегантное решение?

ответ

14
try: 
    bs = a["key"][0][0] 
# Note: the syntax for catching exceptions is different in old versions 
# of Python. Use whichever one of these lines is appropriate to your version. 
except KeyError, IndexError, TypeError: # Python 3 
except (KeyError, IndexError, TypeError): # Python 2 
    bs = [] 
for b in bs: 

И вы можете упаковать его в функцию, если вы не возражаете, более длинные строки:

def maybe_list(f): 
    try: 
    return f() 
    except KeyError, IndexError, TypeError: 
    return [] 

for b in maybe_list(lambda: a["key"][0][0]): 
+2

Хороший звонок, забыл о философии питон это лучше просить прощения, чем разрешения. Исходя из .NET, где вы пытаетесь избежать как можно большего исключения, потребуется некоторое время. – Davy8

+1

В вашем коде есть ошибка: пожалуйста, измените 'except KeyError, IndexError:' to 'except (KeyError, IndexError):'. В противном случае он будет ловить 'KeyError' только и хранить его в переменной IndexError. –

+0

Кроме того, вы захотите поймать 'TypeError', который будет сброшен, если' bs ['key'] 'содержит что-то, что не является последовательностью. –

2

Что по этому поводу:

try: 
    for b in a['key'][0][0]: 
     # do stuff. 
except KeyError, TypeError, IndexError: 
    # respond appropriately. 
+0

Это будет ловить исключения из «do stuff» также, а не только от поиска списка. –

+0

они должны обрабатываться в блоке 'do stuff' со своими операторами' try/except'. – Peter

+0

Если вы не хотите их обрабатывать. – recursive

3

Я бы написать пользовательский индексатор функционируют следующим образом:

def safe_indexer(obj, *indices): 
    for idx in indices: 
     if not obj: break 

     if hasattr(obj, "get"): 
      obj = obj.get(idx) 
     else: 
      obj = obj[idx] 

    return obj 

Использование:

a = {"key": {0: {0: "foo"} } }; 
print safe_indexer(a, "key", 0, 0) 
print safe_indexer(a, "bad", 0, 0) 

Выход:

foo 
None 
+0

Хм, мне это нравится. Если я нахожу, что чаще встречаюсь с этим шаблоном, я, вероятно, буду использовать это. Пока мне просто нужно одноразовое дело, так что Джон проще. – Davy8

+0

Быстрый вопрос, новый для Python, что означает * перед индексами? – Davy8

+1

Это означает, что это список параметров. Другими словами, все последующие аргументы объединяются в список под названием «индексы». Таким образом, вам не нужно явно передавать список. Вместо этого просто используйте индексы непосредственно в качестве аргументов для safe_indexer. – recursive

Смежные вопросы