A adição do collections.defaultdict
Python 2.5 reduziu bastante a necessidade dict
do setdefault
método. Esta pergunta é para a nossa educação coletiva:
- O que
setdefault
ainda é útil hoje em Python 2.6 / 2.7? - Quais casos de uso populares de
setdefault
foram substituídoscollections.defaultdict
?
python
dictionary
setdefault
Eli Bendersky
fonte
fonte
Respostas:
Você poderia dizer que
defaultdict
é útil para definir padrões antes de preencher o ditado esetdefault
é útil para definir padrões durante ou após o preenchimento do ditado .Provavelmente o caso de uso mais comum: Agrupando itens (em dados não classificados, senão use
itertools.groupby
)Às vezes, você deseja garantir a existência de chaves específicas após a criação de um ditado.
defaultdict
não funciona nesse caso, porque cria apenas chaves em acesso explícito. Pense que você usa algo HTTP-ish com muitos cabeçalhos - alguns são opcionais, mas você deseja padrões para eles:fonte
defaultdict
. Você pode dar um exemplo do que você quer dizer no primeiro parágrafo?setdefault
. A,defaultdict
por outro lado, não funcionaria se nem todosdefaultvalues
fossem iguais (ou seja, alguns são0
e outros são[]
).headers = dict(optional_headers)
. Para o caso em que os valores padrão não são todos iguais. E o resultado final é o mesmo que se você obtiver os cabeçalhos HTTP primeiro e depois definir os padrões para aqueles que não obteve. E é bastante utilizável se você já tiveroptional_headers
. Experimente o meu código de 2 etapas e compare com o seu, e você verá o que quero dizer.new.setdefault(key, []).append(value)
defaultdict
seja ainda melhor do quesetdefault
(então, onde está o caso de uso agora?). Além disso,ChainMap
lidaria melhor com ohttp
exemplo, IMO.Eu normalmente uso
setdefault
para dict de argumento de palavra-chave, como nesta função:É ótimo para ajustar argumentos em wrappers em torno de funções que recebem argumentos de palavras-chave.
fonte
defaultdict
é ótimo quando o valor padrão é estático, como uma nova lista, mas não tanto se for dinâmico.Por exemplo, preciso de um dicionário para mapear seqüências de caracteres para ints exclusivos.
defaultdict(int)
sempre usará 0 para o valor padrão. Da mesma forma,defaultdict(intGen())
sempre produz 1.Em vez disso, usei um ditado regular:
Observe que isso
dict.get(key, nextID())
é insuficiente, porque também preciso consultar esses valores posteriormente.intGen
é uma classe minúscula que eu construo que incrementa automaticamente um int e retorna seu valor:Se alguém tem uma maneira de fazer isso,
defaultdict
eu adoraria vê-lo.fonte
intGen
poritertools.count().next
.nextID()
O valor de será incrementado toda vez quemyDict.setdefault()
for chamado, mesmo que o valor retornado não seja usado como astrID
. Isso parece um desperdício de alguma forma e ilustra uma das coisas que eu não gostosetdefault()
em geral - a saber, que ele sempre avalia seudefault
argumento se é ou não usado.defaultdict
:myDict = defaultdict(lambda: nextID())
. Mais tarde,strID = myDict[myStr]
no circuito.myDict = defaultdict(nextID)
?Eu uso
setdefault()
quando quero um valor padrão em umOrderedDict
. Não é uma coleção Python padrão que faz as duas coisas, mas não são maneiras de implementar tais coleção a.fonte
Como a maioria das respostas declara
setdefault
oudefaultdict
permite definir um valor padrão quando uma chave não existe. No entanto, gostaria de salientar uma pequena ressalva em relação aos casos de uso desetdefault
. Quando o interpretador Pythonsetdefault
é executado, ele sempre avalia o segundo argumento da função, mesmo que a chave exista no dicionário. Por exemplo:Como você pode ver,
print
também foi executado mesmo que 2 já existissem no dicionário. Isso se torna particularmente importante se você planeja usar,setdefault
por exemplo, uma otimização comomemoization
. Se você adicionar uma chamada de função recursiva como o segundo argumentosetdefault
, não obteria nenhum desempenho, pois o Python sempre chamaria a função recursivamente.Como a memorização foi mencionada, uma alternativa melhor é usar o decorador functools.lru_cache se você considerar aprimorar uma função com memorização. O lru_cache lida melhor com os requisitos de armazenamento em cache para uma função recursiva.
fonte
Como Muhammad disse, há situações em que você apenas deseja definir um valor padrão. Um ótimo exemplo disso é uma estrutura de dados que é preenchida primeiro e depois consultada.
Considere um trie. Ao adicionar uma palavra, se um subnó for necessário, mas não presente, ele deverá ser criado para estender o trie. Ao consultar a presença de uma palavra, um subnó ausente indica que a palavra não está presente e não deve ser criada.
Um padrão não pode fazer isso. Em vez disso, um ditado regular com os métodos get e setdefault deve ser usado.
fonte
Teoricamente falando,
setdefault
ainda seria útil se algumas vezes você deseja definir um padrão e outras não. Na vida real, não encontrei um caso de uso assim.No entanto, um caso de uso interessante surge da biblioteca padrão (Python 2.6, _threadinglocal.py):
Eu diria que usar
__dict__.setdefault
é um caso bastante útil.Editar : por acaso, este é o único exemplo na biblioteca padrão e está em um comentário. Portanto, pode não ser um caso suficiente para justificar a existência de
setdefault
. Ainda assim, aqui está uma explicação:Os objetos armazenam seus atributos no
__dict__
atributo Por acaso, o__dict__
atributo pode ser gravado a qualquer momento após a criação do objeto. Também é um dicionário, não umdefaultdict
. Não é sensato que objetos no caso geral tenham__dict__
como umdefaultdict
porque isso tornaria cada objeto tendo todos os identificadores legais como atributos. Portanto, não posso prever nenhuma alteração nos objetos Python se livrando__dict__.setdefault
, além de excluí-los completamente se não forem úteis.fonte
__dict__
é pela implementação de umdict
, não umdefaultdict
.setdefault
ficar em Python, mas é curioso ver que agora é quase inútil.setdefault
explicita que você está atribuindo a um ditado por meio de uma chave que pode ou não existir e, se não existir, você deseja que ele seja criado com um valor padrão: por exemplod.setdefault(key,[]).append(value)
. Em outras partes do programa que você fazalist=d[k]
, onde k é calculado, e você quer uma exceção lançada se k não está em d (que com um defaultdict pode exigirassert k in d
ou mesmoif not ( k in d): raise KeyError
Uma desvantagem de
defaultdict
overdict
(dict.setdefault
) é que umdefaultdict
objeto cria um novo item TODAS as chaves inexistentes são fornecidas (por exemplo==
, com ,print
). Além disso, adefaultdict
classe geralmente é muito menos comum que adict
classe, é mais difícil serializá-la IME.As funções do PS IMO | métodos que não pretendem alterar um objeto, não devem modificar um objeto.
fonte
defaultdict(lambda l=[]: l)
.Aqui estão alguns exemplos de setdefault para mostrar sua utilidade:
fonte
Reescrevi a resposta aceita e facilei para os novatos.
Além disso, categorizei os métodos como referência:
fonte
Uso setdefault frequentemente quando, obtém isso, definindo um padrão (!!!) em um dicionário; de certa forma, o dicionário os.environ:
Menos sucintamente, isso se parece com isso:
Vale ressaltar que você também pode usar a variável resultante:
Mas isso é menos necessário do que era antes da existência dos decretos-padrão.
fonte
Outro caso de uso que acho que não foi mencionado acima. Às vezes, você mantém um ditado de cache pelos objetos por seu ID, onde a instância principal está no cache e deseja definir o cache quando estiver ausente.
Isso é útil quando você sempre deseja manter uma única instância por ID distinto, independentemente de como você obtém um objetivo a cada vez. Por exemplo, quando os atributos do objeto são atualizados na memória e o salvamento no armazenamento é adiado.
fonte
Um caso de uso muito importante que encontrei:
dict.setdefault()
é ótimo para código multithread quando você quer apenas um único objeto canônico (ao contrário de vários objetos que são iguais).Por exemplo, o
(Int)Flag
Enum no Python 3.6.0 possui um erro : se vários threads competem por um(Int)Flag
membro composto , pode haver mais de um:A solução é usar
setdefault()
como a última etapa de salvar o membro composto calculado - se outro já tiver sido salvo, ele será usado no lugar do novo, garantindo membros Enum exclusivos.fonte
[Editar] Muito errado!O setdefault sempre acionava a long_computation, o Python estava ansioso.
Expandindo a resposta de Tuttle. Para mim, o melhor caso de uso é o mecanismo de cache. Ao invés de:
que consome 3 linhas e 2 ou 3 pesquisas,
gostaria de escrever:fonte
long_computation(x)
é chamado apenas sex not in memo
. Considerando que no segundo,long_computation(x)
é sempre chamado. Somente a atribuição é condicional, o código equivalentesetdefault
seria semelhante a:v = long_computation(x)
/if x not in memo:
/memo[x] = v
.Eu gosto da resposta dada aqui:
http://stupidpythonideas.blogspot.com/2013/08/defaultdict-vs-setdefault.html
Em resumo, a decisão (em aplicativos que não sejam críticos para o desempenho) deve ser tomada com base em como você deseja lidar com a pesquisa de chaves vazias rio abaixo ( viz.
KeyError
Versus valor padrão).fonte
O caso de uso diferente para
setdefault()
é quando você não deseja substituir o valor de uma chave já configurada.defaultdict
sobrescreve, enquantosetdefault()
não. Para dicionários aninhados, geralmente é o caso de você desejar definir um padrão apenas se a chave ainda não estiver definida, porque você não deseja remover o subdicionário atual. É quando você usasetdefault()
.Exemplo com
defaultdict
:setdefault
não substitui:fonte