Python 检查dict键以确保所需的键始终存在,并且dict在定义的一组名称之外没有其他键名称

Python 检查dict键以确保所需的键始终存在,并且dict在定义的一组名称之外没有其他键名称,python,dictionary,Python,Dictionary,我有一个python的dict,它遵循以下通用格式: {'field': ['$.name'], 'group': 'name', 'function': 'some_function'} 我想对dict做一些预检查,以确保“field”始终存在,并且除了“group”和“function”之外没有其他键存在,这两个键都是可选的 我知道我可以通过使用一个长而不整洁的if语句来做到这一点,但我想一定有一个更干净的方法 这就是我目前拥有的: if(('field'在dict_name和len(di

我有一个python的dict,它遵循以下通用格式:

{'field': ['$.name'], 'group': 'name', 'function': 'some_function'}
我想对dict做一些预检查,以确保“field”始终存在,并且除了“group”和“function”之外没有其他键存在,这两个键都是可选的

我知道我可以通过使用一个长而不整洁的if语句来做到这一点,但我想一定有一个更干净的方法

这就是我目前拥有的:

if(('field'在dict_name和len(dict_name.keys())==1)或
(“组”在dict_name和len中(dict_name.keys())==2)或
(“函数”在dict_name和len中(dict_name.keys())==2)或
(dict_name中的'group'和dict_name和len中的'function'(dict_name.keys())==3))
本质上,我首先检查“字段”是否存在,因为这是必需的。然后我检查它是否是唯一的键(这很好),或者它是“组”旁边的键而不是其他键,或者是“功能”旁边的键而不是其他键,或者是“组”和“功能”旁边的键而不是其他键


是否有更整洁的方法检查提供的钥匙只有这3把钥匙,其中两把是可选的?

您可以使用
设置允许的钥匙,并使用内置功能检查dict的钥匙:

allowed_key={'field','group','function'}
如果d中有“字段”和“全部”(输入d中允许的\u键):
通过
这实际上相当于
集合的方法:

测试集合中的每个元素是否在其他元素中

因此,通过将dict的键强制转换到一个集合并检查它们是否是允许的键的子集,这可以变得更加紧凑:

allowed_key={'field','group','function'}
如果d中有“字段”并设置(d)。IsubSet(允许的\u键):
通过

就我而言,您想检查一下

  • 集合
    {'field'}
    始终包含在dict键集合中
  • dict密钥集始终包含在集合
    {'field','group','function'}
  • 所以只需编写代码

    required_fields = {'field'}
    allowed_fields = required_fields | {'group', 'function'}
    
    d = {'field': 123}  # Set any value here
    
    if required_fields <= d.keys() <= allowed_fields:
        print("Yes!")
    else:
        print("No!")
    
    required_fields={'field'}
    允许的_字段=必需的_字段|{'group','function'}
    d={'field':123}#在此处设置任何值
    如果需要,_fields返回一个原始数据支持的
    集。您可以利用这一点编写一个非常简洁的测试:

    allowed = {'field', 'group', 'function'}
    
    if 'field' in dict_name and dict_name.keys() <= allowed:
        ...
    
    除了可读性之外,在某些情况下使用keys视图时,使用运算符是唯一可能的。例如,以下操作无法运行:

    dict_name.keys().issubset(allowed)
    
    但以下方法效果很好:

    dict_name.keys() <= allowed
    
    但这可能会将
    dict_name.keys()
    包装到一个不必要的
    set
    对象中。同时,

    allowed >= dict_name.keys()
    

    将实际翻转运算符并使用
    您还可以使用验证包,如
    模式


    是的,通过将您的dict转换为:

    从输入导入列表,可选
    从数据类导入数据类
    @数据类
    类别MyDataclass:
    字段:列表[str]
    组:可选[str]=无
    函数:可选[str]=None
    结果=MyDataclass([“$.name”],“name”,“some_函数”)
    #或者,相当于:
    结果=MyDataclass(字段=[“$.name”],group=“name”,function=“some_function”)
    #使用result.field、result.group、result.function访问
    
    要直接回答您的问题,您可以编写以下内容,当输入字典中缺少字段时,它将引发异常:

    dict_name={'field':['$.name'],'group':'name','function':'some_function'}
    MyDataclass(*dict_名称)
    
    请注意,由于使用了splat操作符,上述操作仅在键为字符串时有效。(
    *

    转换为数据类后,您可以安全地使用它,并确保它具有字段。这不太容易出错,因为它可以防止在代码的不同部分混淆检查缺失参数的dict和未检查的dict。请参阅,以获取从理论角度的完整解释

    数据类是Python中的惯用方式,类似于对象(字典)是JavaScript中的惯用方式。此外,如果您使用的IDE支持mypy/pyer/pep484,那么您将获得对象的类型提示由于PEP 484的双向性,这意味着如果您创建了一个缺少字段的dict,并将其传递给一个将其转换为数据类的函数,则类型检查器可能能够检查错误。

    您可以使用将数据类转换回dict


    另一个选项是namedtuple。

    不错!我在解释器中玩了一会儿,得到了
    d.keys()
    issubset
    的属性错误。但我不知道你可以使用显式运算符。感谢你的教育:)联盟可能不会超过三个要素。实际上,3应该是
    len(允许)
    。这确保了
    dict_name.keys()
    不会引入任何新的elements@Kolay.Ne我想你需要像这样用
    set
    包装
    d.keys()
    set(d.keys())
    ?@CristianGutu这是不必要的,
    dict.keys
    返回一个类似set的视图对象。@CristianGutu,是的,这就是我的代码以前的样子。请查看我的答案版本的历史,以便更好地了解发生了什么变化,您很可能会理解为什么(更正我以前的评论)@CristianGutu实际上可能有一个很好的理由去做
    set(d)
    ,而不是
    d.keys()
    :效率。有了这里代码中的数据,我认为
    {'group':'name','function':'func'}
    将根据您的第二行(和第三行)传递
    必填字段得到了约400 ns。您是对的,我没有注意到,正如我所知,必须有更好的解决方案DataClass是Python 3.7中的新功能,为任何人wondering@AaronF我们现在无法控制的大多数系统至少都有Python3.6。当您完成开发时,大多数系统可能已经有了Python3.7
    
    dict_name.keys().issubset(allowed)
    
    dict_name.keys() <= allowed
    
    allowed.issuperset(dict_name.keys())
    
    allowed >= dict_name.keys()
    
    from schema import Schema, And
    
    my_schema = Schema({
        'field': And(str, len),
        'group': And(str, len),
        'function': And(str, len)
    })
    
    data = {
        'field': 'Hello',
        'group': 'This is a group',
        'function': 'some_function'
    }
    
    my_schema.validate(data)