Ответ 1
>>> d1 = dict(a=1, b=2, c=3, d=4)
>>> d2 = dict(a=1, b=2)
>>> set(d2.items()).issubset( set(d1.items()) )
True
И наоборот:
>>> set(d1.items()).issubset( set(d2.items()) )
False
Ограничение: значения словаря должны быть хешируемыми.
Я знаю, что assertDictContainsSubset
может сделать это в python 2.7, но по какой-то причине он устарел в python 3.2. Так есть ли способ утверждать, что dict содержит другой без assertDictContainsSubset
?
Это кажется не очень хорошим:
for item in dic2:
self.assertIn(item, dic)
любой другой хороший способ? Благодаря
>>> d1 = dict(a=1, b=2, c=3, d=4)
>>> d2 = dict(a=1, b=2)
>>> set(d2.items()).issubset( set(d1.items()) )
True
И наоборот:
>>> set(d1.items()).issubset( set(d2.items()) )
False
Ограничение: значения словаря должны быть хешируемыми.
Хотя я использую pytest, я нашел следующую идею в комментарии. Это сработало очень хорошо для меня, поэтому я подумал, что это может быть полезно здесь:
assert dict1.items() <= dict2.items()
для Python 3 и
assert dict1.viewitems() <= dict2.viewitems()
для Python 2.
Он работает с не хэшируемыми элементами, но вы не можете точно знать, какой элемент в конечном итоге выходит из строя.
Решение John1024 сработало для меня. Однако, в случае сбоя, он только сообщает вам False
, а не показывает, какие ключи не совпадают. Поэтому я попытался избежать устаревшего метода assert, используя другие методы подтверждения, которые будут выводить полезные сообщения об ошибках:
expected = {}
response_keys = set(response.data.keys())
for key in input_dict.keys():
self.assertIn(key, response_keys)
expected[key] = response.data[key]
self.assertDictEqual(input_dict, expected)
Большая проблема с принятым ответом заключается в том, что он не работает, если у вас есть значения без хеширования в значениях ваших объектов. Во-вторых, вы не получаете полезного вывода - тест проходит или терпит неудачу, но не говорит вам, какое поле внутри объекта отличается.
Таким образом, проще просто создать словарь подмножества, а затем проверить это. Таким образом, вы можете использовать метод TestCase.assertDictEquals()
, который даст вам очень полезный отформатированный вывод в вашем тестовом runner, показывающий разницу между фактическим и ожидаемым.
Я думаю, что самый приятный и питонический способ сделать это - простое понимание слова как таковое:
from unittest import TestCase
actual = {}
expected = {}
subset = {k:v for k, v in actual.items() if k in expected}
TestCase().assertDictEqual(subset, expected)
ПРИМЕЧАНИЕ, очевидно, если вы используете свой тест в методе, принадлежащем дочернему классу, который наследует TestCase (как вы почти наверняка должны быть), это просто self.assertDictEqual(subset, expected)
Вот сравнение, которое работает, даже если у вас есть списки в словарях:
superset = {'a': 1, 'b': 2}
subset = {'a': 1}
common = { key: superset[key] for key in set(superset.keys()).intersection(set(subset.keys())) }
self.assertEquals(common, subset)
Это отвечает на более широкий вопрос, чем вы просите, но я использую это в своих тестовых жгутах, чтобы узнать, содержит ли словарь container
что-то похожее на словарь contained
. Это проверяет ключи и значения. Кроме того, вы можете использовать ключевое слово 'ANYTHING'
, чтобы указать, что вам все равно, как он соответствует.
def contains(container, contained):
'''ensure that `contained` is present somewhere in `container`
EXAMPLES:
contains(
{'a': 3, 'b': 4},
{'a': 3}
) # True
contains(
{'a': [3, 4, 5]},
{'a': 3},
) # True
contains(
{'a': 4, 'b': {'a':3}},
{'a': 3}
) # True
contains(
{'a': 4, 'b': {'a':3, 'c': 5}},
{'a': 3, 'c': 5}
) # True
# if an `contained` has a list, then every item from that list must be present
# in the corresponding `container` list
contains(
{'a': [{'b':1}, {'b':2}, {'b':3}], 'c':4},
{'a': [{'b':1},{'b':2}], 'c':4},
) # True
# You can also use the string literal 'ANYTHING' to match anything
contains(
{'a': [{'b':3}]},
{'a': 'ANYTHING'},
) # True
# You can use 'ANYTHING' as a dict key and it indicates to match the corresponding value anywhere
# below the current point
contains(
{'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
contains(
{'a': [ {'x':1, 'b':'SOMETHING'}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
contains(
{'a': [ {'x':1,'b1':{'b2':{'c':'SOMETHING'}}}]},
{'a': {'ANYTHING': 'SOMETHING', 'x':1}},
) # True
'''
ANYTHING = 'ANYTHING'
if contained == ANYTHING:
return True
if container == contained:
return True
if isinstance(container, list):
if not isinstance(contained, list):
contained = [contained]
true_count = 0
for contained_item in contained:
for item in container:
if contains(item, contained_item):
true_count += 1
break
if true_count == len(contained):
return True
if isinstance(contained, dict) and isinstance(container, dict):
contained_keys = set(contained.keys())
if ANYTHING in contained_keys:
contained_keys.remove(ANYTHING)
if not contains(container, contained[ANYTHING]):
return False
container_keys = set(container.keys())
if len(contained_keys - container_keys) == 0:
# then all the contained keys are in this container ~ recursive check
if all(
contains(container[key], contained[key])
for key in contained_keys
):
return True
# well, we're here, so I guess we didn't find a match yet
if isinstance(container, dict):
for value in container.values():
if contains(value, contained):
return True
return False
В Python 3 и Python 2.7 вы можете создать подобный множеству "вид элемента" для dict без копирования каких-либо данных. Это позволяет использовать операторы сравнения для проверки отношения подмножества.
В Python 3 это выглядит так:
# Test if d1 is a sub-dict of d2
d1.items() <= d2.items()
# Get items in d1 not found in d2
difference = d1.items() - d2.items()
В Python 2.7 вы можете использовать метод viewitems()
вместо items()
для достижения того же результата.
В Python 2.6 и ниже лучше всего перебирать ключи в первом диктовке и проверять включение во втором.
# Test if d1 is a subset of d2
all(k in d2 and d2[k] == d1[k] for k in d1)
Вместо этого вы можете использовать метод assertGreaterEqual().
users = {'id': 28027, 'email': '[email protected]','created_at': '2005-02-13'}
data = {"email": "[email protected]"}
self.assertGreaterEqual(user.items(), data.items())