Por que dict.get (key) em vez de dict [key]?


651

Hoje, me deparei com o dictmétodo getque, dado uma chave no dicionário, retorna o valor associado.

Para que finalidade essa função é útil? Se eu quisesse encontrar um valor associado a uma chave em um dicionário, posso simplesmente fazê dict[key]-lo, e ele retornará a mesma coisa:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")

1
dictionary["foo"]e dictionary.get("foo")se comportar de maneira diferente, no entanto.
Niklas B.

34
dictionary.get("Age") é o mesmo que escrever dictionary["Age"] or None para que ele lida com implicitamente KeyError exceção
yosemite_k

5
@yosemite_k Talvez eu esteja perdendo algum contexto aqui, mas dictionary['non-existent key'] or Nonedeveria e ainda aumenta um KeyErrorpara mim (até a v3.6). Pode explicar o que quer dizer?
Nivk 31/12/19

O dicionário @nivk ['chave inexistente'] gera erro, e esse erro deve ser tratado explicitamente. se você usar dictionary.get () (que literalmente funciona como dictionary ['inexistent key'] ou None), essa exceção é implicitamente tratada.
yosemite_k

Respostas:


993

Permite fornecer um valor padrão se a chave estiver ausente:

dictionary.get("bogus", default_value)

retorna default_value(o que você escolher), enquanto

dictionary["bogus"]

aumentaria a KeyError.

Se omitido, default_valueé None, tal que

dictionary.get("bogus")  # <-- No default specified -- defaults to None

retorna Nonecomo

dictionary.get("bogus", None)

seria.


1
Seria o mesmo que dictionary.get("bogus") or my_default? Eu já vi pessoas usá-lo em alguns casos e fiquei imaginando se há alguma vantagem em usar um em vez do outro (além da legibilidade).
Algorithmatic

15
@MustafaS: Se "bogus"é uma chave em dictionarye dictionary.get("bogus")retorna um valor que avalia a Falso em um contexto booleano (isto é, um valor Falsey), tal como 0 ou uma cadeia vazia, '', em seguida, dictionary.get("bogus") or my_defaultiria avaliar a my_defaultConsiderando que dictionary.get("bogus", my_default)iria retornar o valor Falsey. Então não, dictionary.get("bogus") or my_defaultnão é equivalente a dictionary.get("bogus", my_default). Qual usar depende do comportamento que você deseja.
unutbu

3
@MustafaS: Por exemplo, suponha x = {'a':0}. Então x.get('a', 'foo')retorna, 0mas x.get('a') or 'foo'retorna 'foo'.
unutbu

3
Uma ressalva possível ao usar dictionary.get('key'): Pode ser confuso se os valores no dicionário forem None. Sem especificar o valor de retorno (segundo argumento opcional), não há como verificar se a chave não existia ou se seu valor é None. Nesse caso específico, eu consideraria usar try-except-KeyError.
Aart Goossens

1
Vale ressaltar que a expressão para especificar o valor padrão é avaliada na chamada "get" e, portanto, é avaliada em cada acesso. Uma alternativa clássica (usando um manipulador KeyError ou um predicado) é avaliar o valor padrão apenas se a chave estiver ausente. Isso permite que um fechamento / lambda seja criado uma vez e avaliado em qualquer chave ausente.
Tom Stambaugh

142

Qual é o dict.get()método?

Como já mencionado, o getmétodo contém um parâmetro adicional que indica o valor ausente. A partir da documentação

get(key[, default])

Retorne o valor para key se key 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 apresente a KeyError.

Um exemplo pode ser

>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1

Existem melhorias de velocidade em algum lugar?

Como mencionado aqui ,

Parece que todas as três abordagens agora exibem desempenho semelhante (cerca de 10% uma da outra), mais ou menos independentes das propriedades da lista de palavras.

No início, getera consideravelmente mais lento. No entanto, agora a velocidade é quase comparável, além da vantagem adicional de retornar o valor padrão. Mas, para limpar todas as nossas consultas, podemos testar em uma lista bastante grande (observe que o teste inclui procurar apenas todas as chaves válidas)

def getway(d):
    for i in range(100):
        s = d.get(i)

def lookup(d):
    for i in range(100):
        s = d[i]

Agora cronometrando essas duas funções usando timeit

>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979

Como podemos ver, a pesquisa é mais rápida que a get, pois não há pesquisa de função. Isso pode ser visto atravésdis

>>> def lookup(d,val):
...     return d[val]
... 
>>> def getway(d,val):
...     return d.get(val)
... 
>>> dis.dis(getway)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_ATTR                0 (get)
              6 LOAD_FAST                1 (val)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE        
>>> dis.dis(lookup)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (val)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE  

Onde isso será útil?

Será útil sempre que você desejar fornecer um valor padrão sempre que estiver pesquisando um dicionário. Isso reduz

 if key in dic:
      val = dic[key]
 else:
      val = def_val

Para uma única linha, val = dic.get(key,def_val)

Onde não será útil?

Sempre que você desejar retornar, KeyErrorinformando que a chave específica não está disponível. Retornar um valor padrão também traz o risco de que um valor padrão específico também seja uma chave!

É possível ter getum recurso semelhante dict['key']?

Sim! Precisamos implementar a __missing__subclasse dict.

Um programa de amostra pode ser

class MyDict(dict):
    def __missing__(self, key):
        return None

Uma pequena demonstração pode ser

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'

32
Padrão-ouro de respostas StackOverflow!
Apollo Data


1
Mais um bom teste seria if k in dict and dict[k]:vs if dict.get(k):. Este abrange a situação quando precisamos verificar se existe chave, e se 'sim' - o valor ?, algo como: dict = {1: '', 2: 'some value'}.
TitanFighter 16/09

7
Lembre-se que o valor padrão fica avaliada independentemente do ser valor no dicionário, então ao invés de dictionary.get(value, long_function())se poderia considerar o usodictionary.get(value) or long_function()
Kresimir

Ah, Kresimir, é verdade. Eu recebi essa pergunta em uma das entrevistas que enfrentei (eu não sabia disso quando publicara originalmente esta resposta). Obrigado por me lembrar sobre isso.
Bhargav Rao

32

getleva um segundo valor opcional. Se a chave especificada não existir no seu dicionário, esse valor será retornado.

dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'

Se você não der o segundo parâmetro, Noneserá retornado.

Se você usar a indexação como em dictionary['Year'], as chaves inexistentes aumentarão KeyError.


19

Vou dar um exemplo prático na raspagem de dados da Web usando python, muitas vezes você obterá chaves sem valores; nesses casos, ocorrerá erros se você usar o dicionário ['key'], enquanto o dictionary.get ('key ',' return_otherwise ') não tem problemas.

Da mesma forma, eu usaria '' .join (list) em oposição à list [0] se você tentar capturar um único valor de uma lista.

espero que ajude.

[Editar] Aqui está um exemplo prático:

Digamos que você esteja chamando uma API, que retorna um arquivo JOSN que você precisa analisar. O primeiro JSON se parece com o seguinte:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}

O segundo JOSN é assim:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}

Observe que o segundo JSON está ausente na chave "submitdate_ts", o que é bastante normal em qualquer estrutura de dados.

Portanto, quando você tenta acessar o valor dessa chave em um loop, pode chamá-lo com o seguinte:

for item in API_call:
    submitdate_ts = item["bids"]["submitdate_ts"]

Você poderia, mas isso fornecerá um erro de traceback para a segunda linha JSON, porque a chave simplesmente não existe.

A maneira apropriada de codificar isso pode ser a seguinte:

for item in API_call:
    submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")

{'x': None} existe para evitar que o segundo nível obtenha um erro. É claro que você pode criar mais tolerância a falhas no código se estiver fazendo raspagem. Como primeiro especificando uma condição if


2
Uma boa resposta, postada antes de qualquer uma das outras, que teria sido mais votada e provavelmente aceita, se você tivesse postado alguns exemplos de código (+1 de mim)
Mawg diz que restabelece Monica em

2
@ Makaw Recentemente, tive um projeto de raspagem para minha pesquisa. Ele estava chamando uma API e analisando arquivos JSON basicamente. Eu tive meu RA fazer isso. Um dos principais problemas que ele teve foi chamar a chave diretamente, quando muitas chaves estão realmente ausentes. Vou postar um exemplo no texto acima.
kevin

obrigado por abordar o aspecto multidimensional disso! Parece que você pode simplesmente fazer {} em vez de {'x': None}
bluppfisk

17

O objetivo é fornecer um valor padrão se a chave não for encontrada, o que é muito útil

dictionary.get("Name",'harry')

8

Para que finalidade essa função é útil?

Um uso específico é contar com um dicionário. Vamos supor que você queira contar o número de ocorrências de cada elemento em uma determinada lista. A maneira comum de fazer isso é criar um dicionário em que as chaves sejam elementos e os valores sejam o número de ocorrências.

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

Usando o .get()método, você pode tornar esse código mais compacto e claro:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1

7

Uma dica para estar ciente ao usar .get():

Se o dicionário contiver a chave usada na chamada .get()e seu valor for None, o .get()método retornará Nonemesmo que um valor padrão seja fornecido.

Por exemplo, o seguinte retorna None, não 'alt_value'como o esperado:

d = {'key': None}
d.get('key', 'alt_value')

.get()O segundo valor de apenas será retornado se a chave fornecida NÃO estiver no dicionário, e não se o valor de retorno dessa chamada for None.


1
Este me pegou: \ Uma maneira de resolver isso é ter d.get('key') or 'alt_value', se você sabe que poderia serNone
Daniel Holmes

4

Por que dict.get (key) em vez de dict [key]?

0. Resumo

Comparando com dict[key], dict.getfornece um valor de fallback ao procurar uma chave.

1. Definição

get (key [, padrão]) 4. Tipos internos - documentação do Python 3.6.4rc1

Retorne o valor para key se key 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.

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Problema que resolve.

Caso contrário default value, você deve escrever códigos pesados ​​para lidar com essa exceção.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

Como uma solução conveniente, dict.getintroduz um valor padrão opcional, evitando códigos acima de forma não intencional.

3. Conclusão

dict.get possui uma opção de valor padrão adicional para lidar com a exceção se a chave estiver ausente no dicionário


0

Uma diferença, que pode ser uma vantagem, é que, se estivermos procurando por uma chave que não existe, obteremos None, não como quando usamos a notação de colchetes; nesse caso, receberemos um erro:

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

A última coisa interessante sobre o método get é que ele recebe um argumento opcional adicional para um valor padrão, ou seja, se tentamos obter o valor da pontuação de um aluno, mas o aluno não tem uma chave de pontuação que podemos obter um 0 em vez disso.

Então, ao invés de fazer isso (ou algo semelhante):

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Nós podemos fazer isso:

score = dictionary.get("score", 0)
# score = 0

-1

Com base no uso deve usar este getmétodo.

Exemplo 1

In [14]: user_dict = {'type': False}

In [15]: user_dict.get('type', '')

Out[15]: False

In [16]: user_dict.get('type') or ''

Out[16]: ''

Exemplo2

In [17]: user_dict = {'type': "lead"}

In [18]: user_dict.get('type') or ''

Out[18]: 'lead'

In [19]: user_dict.get('type', '')

Out[19]: 'lead'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.