Retornar nenhum se a chave Dicionário não estiver disponível

489

Eu preciso de uma maneira de obter um valor de dicionário se sua chave existir, ou simplesmente retornar None, se não existir.

No entanto, o Python gera uma KeyErrorexceção se você procurar uma chave que não existe. Eu sei que posso verificar a chave, mas estou procurando algo mais explícito. Existe uma maneira de retornar apenas Nonese a chave não existir?

Spyros
fonte
74
Basta usar em .get(key)vez de[key]
Gabe
12
Um ditado gera uma exceção KeyError. Não "retorna key_error".
2525/11
3
Acessar a chave e capturar a exceção é perfeitamente aceitável no Python. É até um padrão de design bem conhecido e frequentemente usado. Se você retornar None, torna-se impossível armazenar None como um valor, o que pode ser relevante em alguns casos.
Mar
1
Às vezes, você deseja tratar as entradas "Nenhuma" no dicionário e as entradas ausentes da mesma forma; nesse caso, a resposta aceita parece fazer o trabalho muito bem.
Cib
@ Ber Eu editei a pergunta para esclarecer. Você poderia ter feito isso também.
törzsmókus 11/10

Respostas:

813

Você pode usar dict.get()

value = d.get(key)

que retornará Nonese key is not in d. Você também pode fornecer um valor padrão diferente que será retornado em vez de None:

value = d.get(key, "empty")
Tim Pietzcker
fonte
47
Observe que a segunda variante com um fallback padrão ainda retornará Nonese a chave for explicitamente mapeada Noneno dict. Se não é isso que você deseja, você pode usar algo como d.get(key) or "empty".
Cib
15
@cib: Bom ponto, mas a solução tem um problema semelhante - se a chave está mapeado para qualquer valor "Falsas" (como [], "", False, 0.0ou, na verdade None), então sua solução seria sempre voltar 0. Se você espera Nones como valores, precisará fazer a if key in d:verificação explicitamente.
Tim Pietzcker
1
@ cib aplaude por isso, eu não conseguia entender o que estava fazendo de errado aqui.
wobbily_col
@ TimPietzcker - você pode explicar sua resposta? d.get (chave) ou "vazio" no caso de a chave ser mapeada para qualquer valor 'falso' é "vazio" se não me engano.
MiloMinderbinder 02/09/19
@MiloMinderbinder: "empty"será retornado se keynão for uma chave válida d. Não tem nada a ver com o valor que keyestá mapeado.
Tim Pietzcker
63

Não me pergunto mais. Está embutido no idioma.

    >>> ajuda (ditado)

    Ajuda no dict de classe nos módulos internos:

    ditado de classe (objeto)
     | dict () -> novo dicionário vazio
     | dict (mapping) -> novo dicionário inicializado a partir de um objeto de mapeamento
     | pares (chave, valor)
    ...
     |  
     | pegue(...)
     | D.get (k [, d]) -> D [k] se k em D, caso contrário d. d padrão é Nenhum.
     |  
    ...
John La Rooy
fonte
22

Usar dict.get

Retorna o valor da chave se a chave estiver no dicionário, caso contrário, será o padrão. Se o padrão não for fornecido, o padrão será Nenhum, para que esse método nunca gere um KeyError.

Daenyth
fonte
19

Você deve usar o get()método da dictclasse

d = {}
r = d.get('missing_key', None)

Isso resultará em r == None. Se a chave não for encontrada no dicionário, a função get retornará o segundo argumento.

crepúsculo
fonte
19
Você não precisa passar Noneexplicitamente. É o padrão.
Björn Pollex
18

Se você deseja uma solução mais transparente, pode subclassear dictpara obter este comportamento:

class NoneDict(dict):
    def __getitem__(self, key):
        return dict.get(self, key)

>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True
Björn Pollex
fonte
2
@ Marineau: Como eu mencionei em um comentário para outra resposta, o problema com o defaultdicté que ele crescerá cada vez que um elemento que ainda não está lá é solicitado. Isso nem sempre é desejável.
Björn Pollex
@ BjörnPollex Este é de longe o mais elegante. Alguma pista sobre como estender isso para suportar alguma profundidade? Quero dizer fazendo foo['bar']['test']['sss']para voltar Noneem vez de exceção, Depois de uma profundidade que ela começar a dar TypeErrorem vez deKeyError
Nehem
@itsneo. Você pode construir toda a estrutura de NoneDicts. Isso ajudaria no caso de KeyErrorisso acontecer no objeto mais interno. Caso contrário, o problema é que, depois de retornar um Noneobjeto, você não pode mais assiná-lo. Um truque feio seria retornar outro objeto que testa como None. Cuidado, porém, que isso pode levar a erros horríveis.
Magu_ 18/11/2015
@ BjörnPollex Está tudo bem em mudar return dict.get(self, key)para return super().get(key)? Então, se eu decidir usar OrderedDict em vez de dict, por exemplo, não preciso me preocupar em alterar várias linhas de código.
Madeira
@ Wood Sim, isso seria realmente muito melhor!
Björn Pollex
12

Eu costumo usar um padrão para situações como esta. Você fornece um método de fábrica que não aceita argumentos e cria um valor quando vê uma nova chave. É mais útil quando você deseja retornar algo como uma lista vazia em novas chaves ( veja os exemplos ).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
trabalho
fonte
19
O problema defaultdicté que ele continuará crescendo toda vez que um elemento não existente for solicitado.
Björn Pollex 25/05
8

Você pode usar dicto get()método de um objeto , como outros já sugeriram. Como alternativa, dependendo exatamente do que você está fazendo, você poderá usar um try/exceptconjunto como este:

try:
   <to do something with d[key]>
except KeyError:
   <deal with it not being there>

O que é considerado uma abordagem muito "pitônica" para lidar com o caso.

Martineau
fonte
7

Uma solução de uma linha seria:

item['key'] if 'key' in item else None

Isso é útil ao tentar adicionar valores de dicionário a uma nova lista e desejar fornecer um padrão:

por exemplo.

row = [item['key'] if 'key' in item else 'default_value']
imapotatoe123
fonte
5

Como outros já disseram acima, você pode usar get ().

Mas para verificar uma chave, você também pode:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Marek P
fonte
Agora vejo que você já sabe como fazer isso. Eu ia excluir minha postagem, mas deixarei como referência para outras pessoas.
Marek P #
4
Essa abordagem geralmente exige que a chave seja pesquisada duas vezes quando ela estiver lá, o que provavelmente é o motivo do getmétodo.
Martineau 25/05
0

Fiquei surpreso com o que era possível em python2 vs python3. Vou respondê-lo com base no que acabei fazendo pelo python3. Meu objetivo era simples: verificar se uma resposta json no formato de dicionário deu um erro ou não. Meu dicionário é chamado "token" e minha chave que estou procurando é "error". Estou procurando a chave "erro" e, se não estiver lá, configurando-o para o valor Nenhum, então verificando se o valor é Nenhum, se assim for, prossiga com o meu código. Uma instrução else seria manipulada se eu tiver a chave "erro".

if ((token.get('error', None)) is None):
    do something
FastGTR
fonte
-2

Se você pode fazer isso False, também há a função interna hasattr :

e=dict()
hasattr(e, 'message'):
>>> False
Evhz
fonte