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

nim*_*wfc 44 python dictionary

我在 python 中有一个遵循这种通用格式的字典:

{'field': ['$.name'], 'group': 'name', 'function': 'some_function'}
Run Code Online (Sandbox Code Playgroud)

我想对 dict 进行一些预检查,以确保“字段”始终存在,并且除了“组”和“功能”之外没有更多的键存在,这两个都是可选的。

我知道我可以通过使用长而不整洁的 if 语句来做到这一点,但我认为必须有一种更简洁的方法?

这是我目前拥有的:

{'field': ['$.name'], 'group': 'name', 'function': 'some_function'}
Run Code Online (Sandbox Code Playgroud)

本质上,我首先检查“字段”是否存在,因为这是必需的。然后我检查它是否是唯一的键(这很好),或者它是否是“组”旁边的键而没有其他键,或者是“功能”旁边的键而没有其他键,或者是“组”旁边的键和“功能”,没有其他。

是否有一种更整洁的方法来检查提供的密钥是否只有这 3 个密钥,其中两个是可选的?

Kol*_*.Ne 44

就我而言,你想检查一下,

  1. 该集合{'field'}始终包含在您的 dict 键集合中
  2. 你的字典键集总是包含在集合中 {'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!")
Run Code Online (Sandbox Code Playgroud)

除非您有一些特殊条件(例如,互斥键),否则此解决方案可针对任何一组必需和允许的字段进行扩展

(感谢@Duncan 非常优雅的代码缩减)


noɥ*_*ɐɹƆ 16

是的,通过使用数据类转换您的 dict :

from typing import List, Optional
from dataclasses import dataclass

@dataclass
class MyDataclass:
     field: List[str]
     group: Optional[str] = None
     function: Optional[str] = None

result = MyDataclass(["$.name"], "name", "some_function")
# or, equivalently:
result = MyDataclass(field=["$.name"], group="name", function="some_function")

# access with result.field, result.group, result.function
Run Code Online (Sandbox Code Playgroud)

要直接回答您的问题,您可以编写以下内容,当输入字典中缺少字段时,它将抛出异常:

dict_name = {'field': ['$.name'], 'group': 'name', 'function': 'some_function'}

MyDataclass(*dict_name)
Run Code Online (Sandbox Code Playgroud)

请注意,由于使用了 splat 运算符,上述内容仅在您的键是字符串时才有效。( *)

一旦转换为数据类,您就可以放心地使用它,并确保它具有字段。这不太容易出错,因为它可以防止您在代码的不同部分混淆检查缺少参数的字典和未经检查的字典。请参阅Parse, Don't Validate从理论角度获得完整的解释。

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

您可以使用 将数据类转换回字典dataclasses.asdict

另一种选择是namedtuple。


Juh*_*nen 9

您还可以使用验证包,如schema https://pypi.org/project/schema/

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)
Run Code Online (Sandbox Code Playgroud)


Mad*_*ist 7

dict.keys返回一个set视图支持由原始数据。你可以利用它来编写一个非常简洁的测试:

allowed = {'field', 'group', 'function'}

if 'field' in dict_name and dict_name.keys() <= allowed:
    ...
Run Code Online (Sandbox Code Playgroud)

set运算符<=等价于issubset方法。

您可以对第二个条件使用其他设置操作:

allowed >= dict_name.keys()
Run Code Online (Sandbox Code Playgroud)
len(dict_name.keys() | allowed) <= len(allowed)
Run Code Online (Sandbox Code Playgroud)
not (dict_name.keys() - allowed)
Run Code Online (Sandbox Code Playgroud)

除了可读性之外,在某些情况下使用键视图时,使用运算符是唯一的可能性。例如,以下无法运行:

dict_name.keys().issubset(allowed)
Run Code Online (Sandbox Code Playgroud)

但以下工作正常:

dict_name.keys() <= allowed
Run Code Online (Sandbox Code Playgroud)

你可以做

allowed.issuperset(dict_name.keys())
Run Code Online (Sandbox Code Playgroud)

但这很可能包含dict_name.keys()在一个不必要的set对象中。同时,

allowed >= dict_name.keys()
Run Code Online (Sandbox Code Playgroud)

<=由于 Python 的算术运算符如何解析类型,实际上会翻转运算符并使用版本。