Você pode usar get
duas vezes:
example_dict.get('key1', {}).get('key2')
Isso retornará None
se um key1
oukey2
existir não.
Observe que isso ainda pode gerar um AttributeError
if example_dict['key1']
existe, mas não é um dict (ou um objeto do tipo dict com um get
método). O try..except
código que você postou aumentaria uma TypeError
vez seexample_dict['key1']
ser subscrito.
Outra diferença é que os try...except
curtos-circuitos imediatamente após a primeira tecla ausente. A cadeia de get
chamadas não.
Se você deseja preservar a sintaxe, example_dict['key1']['key2']
mas não deseja que ele aumente KeyErrors, use a receita Hasher :
class Hasher(dict):
# https://stackoverflow.com/a/3405143/190597
def __missing__(self, key):
value = self[key] = type(self)()
return value
example_dict = Hasher()
print(example_dict['key1'])
# {}
print(example_dict['key1']['key2'])
# {}
print(type(example_dict['key1']['key2']))
# <class '__main__.Hasher'>
Observe que isso retorna um Hasher vazio quando uma chave está ausente.
Como Hasher
é uma subclasse, dict
você pode usar um Hasher da mesma maneira que você poderia usar um dict
. Todos os mesmos métodos e sintaxe estão disponíveis, os Hashers tratam as chaves ausentes de maneira diferente.
Você pode converter um regular dict
em um Hasher
assim:
hasher = Hasher(example_dict)
e converta a Hasher
para regular com dict
a mesma facilidade:
regular_dict = dict(hasher)
Outra alternativa é ocultar a feiura em uma função auxiliar:
def safeget(dct, *keys):
for key in keys:
try:
dct = dct[key]
except KeyError:
return None
return dct
Portanto, o restante do seu código pode ficar relativamente legível:
safeget(example_dict, 'key1', 'key2')