Подтвердить что ты не робот

Как утверждать, что dict содержит другой dict без assertDictContainsSubset в python?

Я знаю, что assertDictContainsSubset может сделать это в python 2.7, но по какой-то причине он устарел в python 3.2. Так есть ли способ утверждать, что dict содержит другой без assertDictContainsSubset?

Это кажется не очень хорошим:

for item in dic2:
    self.assertIn(item, dic)

любой другой хороший способ? Благодаря

4b9b3361

Ответ 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

Ограничение: значения словаря должны быть хешируемыми.

Ответ 2

Хотя я использую pytest, я нашел следующую идею в комментарии. Это сработало очень хорошо для меня, поэтому я подумал, что это может быть полезно здесь:

assert dict1.items() <= dict2.items()

для Python 3 и

assert dict1.viewitems() <= dict2.viewitems()

для Python 2.

Он работает с не хэшируемыми элементами, но вы не можете точно знать, какой элемент в конечном итоге выходит из строя.

Ответ 3

Решение 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)

Ответ 4

Большая проблема с принятым ответом заключается в том, что он не работает, если у вас есть значения без хеширования в значениях ваших объектов. Во-вторых, вы не получаете полезного вывода - тест проходит или терпит неудачу, но не говорит вам, какое поле внутри объекта отличается.

Таким образом, проще просто создать словарь подмножества, а затем проверить это. Таким образом, вы можете использовать метод 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)

Ответ 5

Вот сравнение, которое работает, даже если у вас есть списки в словарях:

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)

Ответ 6

Это отвечает на более широкий вопрос, чем вы просите, но я использую это в своих тестовых жгутах, чтобы узнать, содержит ли словарь 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

Ответ 7

В 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)

Ответ 8

Вместо этого вы можете использовать метод assertGreaterEqual().

users = {'id': 28027, 'email': '[email protected]','created_at': '2005-02-13'}

data = {"email": "[email protected]"}

self.assertGreaterEqual(user.items(), data.items())