Estou tentando escrever um método de filtro personalizado que usa um número arbitrário de kwargs e retorna uma lista contendo os elementos de uma lista do tipo banco de dados que contém esses kwargs .
Por exemplo, suponha d1 = {'a':'2', 'b':'3'}
e d2
= a mesma coisa. d1 == d2
resulta em Verdadeiro. Mas suponha d2
= a mesma coisa mais um monte de outras coisas. Meu método precisa ser capaz de dizer se d1 em d2 , mas Python não pode fazer isso com dicionários.
Contexto:
Eu tenho uma classe Word, e cada objeto tem propriedades como word
, definition
, part_of_speech
e assim por diante. Quero ser capaz de chamar um método de filtro na lista principal dessas palavras, como Word.objects.filter(word='jump', part_of_speech='verb-intransitive')
. Não consigo descobrir como gerenciar essas chaves e valores ao mesmo tempo. Mas isso poderia ter uma funcionalidade maior fora deste contexto para outras pessoas.
fonte
d1.viewitems() <= d2.viewitems()
. A execução do Timeit mostrou uma melhoria de desempenho de mais de 3x. Se não for hashable, mesmo usando emiteritems()
vez deitems()
leva a uma melhoria de cerca de 1,2x. Isso foi feito usando Python 2.7.items()
retornará visualizações leves em vez de cópias. Nenhuma otimização adicional é necessária.No Python 3, você pode usar
dict.items()
para obter uma visão semelhante a um conjunto dos itens de dicionário. Você pode então usar o<=
operador para testar se uma visualização é um "subconjunto" da outra:No Python 2.7, use o
dict.viewitems()
para fazer o mesmo:No Python 2.6 e abaixo, você precisará de uma solução diferente, como usar
all()
:fonte
d1.items() <= d2.items()
d1.items() <= d2.items()
estão, na verdade, comparando 2 listas de tuplas, sem uma ordem particular, então o resultado final provavelmente não será confiável. Por esse motivo, mudo para a resposta de @blubberdiblub.d1.items() <= d2.items()
é um comportamento indefinido. Isso não está documentado nos documentos oficiais e, o mais importante, não foi testado: github.com/python/cpython/blob/… Portanto, isso depende da implementação.collections.abc.Set
estão disponíveis"Nota para as pessoas que precisam disso para testes de unidade: também há um
assertDictContainsSubset()
método naTestCase
classe do Python .http://docs.python.org/2/library/unittest.html?highlight=assertdictcontainssubset#unittest.TestCase.assertDictContainsSubset
No entanto, ele está obsoleto no 3.2, não sei por que, talvez haja um substituto para ele.
fonte
para chaves e valores, verifique o uso:
set(d1.items()).issubset(set(d2.items()))
se você precisar verificar apenas as chaves:
set(d1).issubset(set(d2))
fonte
d1={'a':1,'b':2}; d2={'a':2,'b':1}
-> o segundo fragmento retornaráTrue
...{'a', 'b'}
é na verdade um subconjunto de{'a', 'b'}
;)Para ser completo, você também pode fazer isso:
No entanto, eu não faço qualquer reclamação sobre velocidade (ou falta dela) ou legibilidade (ou falta dela).
fonte
small.viewitems() <= big.viewitems()
foram promissoras, mas com uma ressalva: se seu programa também pudesse ser usado no Python 2.6 (ou mesmo abaixo), elesd1.items() <= d2.items()
estão, na verdade, comparando 2 listas de tuplas, sem ordem particular, então o resultado final provavelmente não confiável. Por esse motivo, mudo para a resposta de @blubberdiblub. Votado.dict
como classe base? E se não tiver feito isso e ainda se comportar como umdict
? E sesmall
ebig
contiver valores de tipos diferentes em uma chave correspondente que ainda se comportam como dict?False
quando os valores dos ditos passados são diferentes para chaves correspondentes). Ou em outras palavras: a solução para dicts aninhados não é necessariamente uma substituição imediata, dependendo do caso de uso.contexto:
fonte
Minha função com o mesmo propósito, fazendo isso recursivamente:
Em seu exemplo,
dictMatch(d1, d2)
deve retornar True mesmo se d2 tiver outras coisas nele, além de se aplicar também a níveis inferiores:Notas: Pode haver uma solução ainda melhor que evite a
if type(pvalue) is dict
cláusula e se aplique a uma gama ainda maior de casos (como listas de hashes, etc.). Além disso, a recursão não é limitada aqui, portanto, use por sua própria conta e risco. ;)fonte
Aqui está uma solução que também recorre adequadamente às listas e conjuntos contidos no dicionário. Você também pode usar isso para listas contendo dictos etc ...
fonte
Esse problema aparentemente simples me custa algumas horas em pesquisas para encontrar uma solução 100% confiável, então documentei o que encontrei nesta resposta.
Falando de forma "pitônica",
small_dict <= big_dict
seria a forma mais intuitiva, mas uma pena que não funcionará .{'a': 1} < {'a': 1, 'b': 2}
aparentemente funciona no Python 2, mas não é confiável porque a documentação oficial o menciona explicitamente. Vá pesquisar "Resultados diferentes da igualdade são resolvidos de forma consistente, mas não são definidos de outra forma." em esta seção . Sem mencionar que a comparação de 2 dictos em Python 3 resulta em uma exceção TypeError.A segunda coisa mais intuitiva é apenas
small.viewitems() <= big.viewitems()
para Python 2.7 esmall.items() <= big.items()
para Python 3. Mas há uma ressalva: é potencialmente bugado . Se o seu programa puder ser usado em Python <= 2.6, eled1.items() <= d2.items()
está, na verdade, comparando 2 listas de tuplas, sem uma ordem específica, então o resultado final não será confiável e se tornará um bug desagradável em seu programa. Não estou interessado em escrever outra implementação para Python <= 2.6, mas ainda não me sinto confortável se meu código vem com um bug conhecido (mesmo se estiver em uma plataforma sem suporte). Portanto, abandono essa abordagem.Eu me sento com a resposta de @blubberdiblub (o crédito vai para ele):
def is_subdict(small, big): return dict(big, **small) == big
Vale ressaltar que, essa resposta depende do
==
comportamento entre dictos, que está claramente definido em documento oficial, portanto deve funcionar em todas as versões do Python . Vá pesquisar:fonte
Aqui está uma solução recursiva geral para o problema fornecido:
NOTA: O código original iria falhar em certos casos, os créditos pela correção vão para @olivier-melançon
fonte
if not set(value) <= set(superset[key])
Se você não se importa de usar
pydash
,is_match
existe um que faz exatamente isso:fonte
Eu sei que esta pergunta é antiga, mas aqui está minha solução para verificar se um dicionário aninhado faz parte de outro dicionário aninhado. A solução é recursiva.
fonte
Esta função funciona para valores não hashable. Também acho que é claro e fácil de ler.
fonte
Uma implementação recursiva curta que funciona para dicionários aninhados:
Isso consumirá os dictos a e b. Se alguém souber de uma boa maneira de evitar isso sem recorrer a soluções parcialmente iterativas como em outras respostas, por favor me diga. Eu precisaria de uma maneira de dividir um dicionário em cabeçalho e cauda com base em uma chave.
Este código é mais útil como um exercício de programação e provavelmente é muito mais lento do que outras soluções aqui que misturam recursão e iteração. A solução do @Nutcracker é muito boa para dicionários aninhados.
fonte
a
(e qualquer primeiro valor subsequente)popitem
achados. Ele também deve examinar outros itens no mesmo nível. Eu tenho pares de dicts aninhados onde retorna a resposta errada. (difícil apresentar um exemplo à prova de futuro aqui, pois se baseia na ordem depopitem
)Use este objeto wrapper que fornece comparação parcial e diferenças legais:
fonte