为了账号安全,请及时绑定邮箱和手机立即绑定

通过理解更新列表中的字典项

通过理解更新列表中的字典项

慕码人8056858 2021-09-14 20:36:51
我有一本字典,我想用它作为模板来生成多个带有更新字典项的字典。此列表应用作 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 resulttemplate = {'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}但我无法通过变量传递键值。创建 dict 只是为了解压它对我来说听起来适得其反。
查看完整描述

1 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

特别是我不确定...

关于在推导中更新 Python dicts 的事情有点复杂,因为它们是可变的。在为什么 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 步。您计算这些值的笛卡尔积,这意味着您可以从每个values列表中获取一个值的所有可能组合。此操作的结果如下:


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'}]


查看完整回答
反对 回复 2021-09-14
  • 1 回答
  • 0 关注
  • 170 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信