Обновление словарных элементов в списке через понимание - PullRequest
0 голосов
/ 12 декабря 2018

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

Я использую следующую конструкцию в своем коде (проверки исключены):

def _f(template,**kwargs):
    result = [template]
    for key, value in kwargs.items():
        result = [dict(template_item,**dict([(key,v)])) for v in value for template_item in result]
    return result

template = {'a': '', 'b': '', 'x': 'asdf'}

r = _f(template, a=[1,2],b=[11,22])

pprint(r)

[{'a': 1, 'b': 11, 'x': 'asdf'},
 {'a': 2, 'b': 11, 'x': 'asdf'},
 {'a': 1, 'b': 22, 'x': 'asdf'},
 {'a': 2, 'b': 22, 'x': 'asdf'}]

Я хотел быспросите, достаточно ли хороша конструкция, используемая для построения - возможно, она может быть написана более эффективно.

Это правильный способ подготовки данных тестирования?

РЕДАКТИРОВАТЬ: Особенно яне уверен насчет

[dict(template_item,**dict([(key,v)])) for v in value for template_item in result]

и

dict(template_item,**dict([(key,v)])) 

До того, как я подумал о dict.update (), но он не подходит для понимания, потому что он не возвращает словарь.

затемя думал о простом синтаксисе, таком как

d = {'aa': 11, 'bb': 22}
dict(d,x=33,y=44)
    {'aa': 11, 'bb': 22, 'x': 33, 'y': 44}

, но мне не удалось передать значение ключа через переменную.И создание дикта только для распаковки для меня звучит контрпродуктивно.

1 Ответ

0 голосов
/ 12 декабря 2018

Специально, я не уверен насчет ...

В обновлении Python есть много сложностей, поскольку они изменчивы.В Почему python dict.update () не возвращает объект? лучший ответ предлагает ваше текущее решение.Лично я бы, наверное, пошел с обычным циклом for, чтобы убедиться, что код разборчивый.

Это правильный способ подготовки данных тестирования?

  1. Обычно в модульных тестах вы тестируете как крайние, так и обычные случаи (однако вы не хотите повторяться).Обычно вы хотите разделить тесты, чтобы у каждого было свое имя, объясняющее, почему оно есть, и, возможно, некоторые другие данные, которые могли бы помочь постороннему понять, почему важно убедиться, что этот сценарий работает правильно.Если поместить все сценарии в один список, а затем запустить тест для каждого из них, не предоставляя читателю дополнительный контекст (в форме, по крайней мере, названия теста), читателю будет сложнее различать случаи и судить, все ли они являютсядействительно необходимо.
  2. Помещение каждого из сценариев в отдельный тестовый случай может иногда показаться утомительным, но если какой-либо из тестов не пройден, вы можете сразу сказать, какая часть программного обеспечения дает сбой.Если вам кажется, что вы пишете слишком много модульных тестов, возможно, некоторые из них охватывают одни и те же сценарии.
  3. Когда работа с модульными тестами редко является главным приоритетом.Обычно важнее всего сделать количество тестов минимальным, но достаточным для обеспечения правильной работы программного обеспечения.Другая приоритетная задача - сделать тесты понятными.Ниже вы найдете другой подход (не обязательно более производительный, но, надеюсь, более разборчивый).

Альтернативное решение

Вы можете использовать itertools.product для упрощения кода.Параметр template можно удалить (поскольку вы можете передать имена переменных шаблона и их возможные значения в **kwargs):

from pprint import pprint
import itertools

def _f(**kwargs):
    keys, values = zip(*(kwargs.items())) # 1.
    subsets = [subset for subset in itertools.product(*values)] # 2.
    return [
        {key: value for key, value in zip(keys, subset)} for subset in subsets
    ] # 3.

r = _f(a=[1, 2], b=[11, 22], x=['asdf'])
pprint(r)

Теперь, что происходит на каждом из этих шагов:

Шаг 1. Вы разделяете ключевое слово dict на ключи и значения.Это важно, так что вы будете фиксировать порядок повторения этих аргументов каждый раз.На этом этапе ключи и значения выглядят следующим образом:

keys = ('a', 'b', 'x') 
values = ([1, 2], [11, 22], ['asdf'])

Шаг 2. Вы вычисляете декартово произведение значений, что означает, что вы получаете все возможные комбинации взятия значения из каждого из * 1034.* списки.Результат этой операции выглядит следующим образом:

subsets = [(1, 11, 'asdf'), (1, 22, 'asdf'), (2, 11, 'asdf'), (2, 22, 'asdf')]

Шаг 3. Теперь вам нужно сопоставить каждый из ключей с соответствующими значениями в каждом из подмножеств, отсюда и списки, и определения слов, результат должен бытьименно то, что вы рассчитали, используя свой предыдущий метод:

[{'a': 1, 'b': 11, 'x': 'asdf'},
 {'a': 1, 'b': 22, 'x': 'asdf'},
 {'a': 2, 'b': 11, 'x': 'asdf'},
 {'a': 2, 'b': 22, 'x': 'asdf'}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...