在业务开发中,我们常遇到需要动态校验字典中多个键值对是否符合用户自定义规则的需求,比如用户配置商品筛选条件,要求价格大于100且小于500,同时库存大于0,这类复合比较条件的解析和验证需要兼顾灵活性与安全性。

核心设计思路
要实现安全高效的解析验证,核心是将用户自定义的复合条件转化为结构化的规则对象,再遍历规则逐条匹配字典键值对。整体分为三个步骤:
- 定义规则的结构化格式,支持基础比较和逻辑组合
- 解析用户输入的规则字符串,生成可执行的规则树
- 遍历规则树,匹配目标字典的键值对,返回校验结果
规则结构化定义
我们首先定义基础比较规则和逻辑组合规则的结构,基础比较规则包含字段名、比较运算符、目标值三个核心元素,逻辑组合规则支持与、或、非三种逻辑。以下是规则对应的Python类定义:
from typing import Dict, Any, List, Union, Optional
# 基础比较运算符枚举
COMPARE_OPS = {
"eq": lambda a, b: a == b,
"ne": lambda a, b: a != b,
"gt": lambda a, b: a > b,
"lt": lambda a, b: a < b,
"gte": lambda a, b: a >= b,
"lte": lambda a, b: a <= b,
"in": lambda a, b: a in b,
"not_in": lambda a, b: a not in b
}
class BaseCompareRule:
"""基础比较规则"""
def __init__(self, field: str, op: str, value: Any):
self.field = field
self.op = op
self.value = value
if op not in COMPARE_OPS:
raise ValueError(f"不支持的比较运算符: {op}")
def match(self, data: Dict[str, Any]) -> bool:
"""校验字典是否满足当前规则"""
if self.field not in data:
return False
field_value = data[self.field]
# 类型兼容处理,避免不同类型比较报错
try:
return COMPARE_OPS[self.op](field_value, self.value)
except TypeError:
return False
class LogicRule:
"""逻辑组合规则"""
def __init__(self, logic_type: str, rules: List[Union[BaseCompareRule, 'LogicRule']]):
self.logic_type = logic_type # and/or/not
self.rules = rules
if logic_type not in ("and", "or", "not"):
raise ValueError(f"不支持的逻辑类型: {logic_type}")
def match(self, data: Dict[str, Any]) -> bool:
"""校验字典是否满足当前逻辑规则"""
if self.logic_type == "and":
return all(rule.match(data) for rule in self.rules)
elif self.logic_type == "or":
return any(rule.match(data) for rule in self.rules)
elif self.logic_type == "not":
if len(self.rules) != 1:
raise ValueError("not逻辑只能包含一个子规则")
return not self.rules[0].match(data)
规则解析实现
接下来实现规则解析函数,支持将用户传入的结构化规则字典转化为对应的规则对象,同时做参数校验,避免无效规则导致运行时错误:
def parse_rule(rule_dict: Dict[str, Any]) -> Union[BaseCompareRule, LogicRule]:
"""解析规则字典为规则对象"""
if not isinstance(rule_dict, dict):
raise TypeError("规则必须是字典类型")
# 处理基础比较规则
if "field" in rule_dict and "op" in rule_dict and "value" in rule_dict:
return BaseCompareRule(
field=rule_dict["field"],
op=rule_dict["op"],
value=rule_dict["value"]
)
# 处理逻辑组合规则
if "logic" in rule_dict and "rules" in rule_dict:
logic_type = rule_dict["logic"]
sub_rules = [parse_rule(sub_rule) for sub_rule in rule_dict["rules"]]
return LogicRule(logic_type=logic_type, rules=sub_rules)
raise ValueError("无效的规则格式")
完整校验流程示例
下面是完整的校验函数和使用示例,演示如何解析用户自定义规则并验证字典是否满足要求:
def validate_dict(data: Dict[str, Any], rule_dict: Dict[str, Any]) -> bool:
"""校验字典是否满足用户自定义规则"""
try:
rule = parse_rule(rule_dict)
return rule.match(data)
except (TypeError, ValueError) as e:
# 规则解析失败返回False,也可根据需求记录日志
print(f"规则解析失败: {e}")
return False
# 用户自定义复合规则:价格大于100且小于500,同时库存大于0
user_rule = {
"logic": "and",
"rules": [
{"field": "price", "op": "gt", "value": 100},
{"field": "price", "op": "lt", "value": 500},
{"field": "stock", "op": "gt", "value": 0}
]
}
# 测试数据1:满足所有条件
test_data_1 = {"price": 300, "stock": 20, "name": "测试商品"}
print(validate_dict(test_data_1, user_rule)) # 输出 True
# 测试数据2:价格不满足
test_data_2 = {"price": 80, "stock": 20, "name": "测试商品"}
print(validate_dict(test_data_2, user_rule)) # 输出 False
# 测试数据3:库存不满足
test_data_3 = {"price": 300, "stock": 0, "name": "测试商品"}
print(validate_dict(test_data_3, user_rule)) # 输出 False
# 复杂规则示例:价格大于500 或 (价格小于200且库存大于10)
complex_rule = {
"logic": "or",
"rules": [
{"field": "price", "op": "gt", "value": 500},
{
"logic": "and",
"rules": [
{"field": "price", "op": "lt", "value": 200},
{"field": "stock", "op": "gt", "value": 10}
]
}
]
}
test_data_4 = {"price": 150, "stock": 15}
print(validate_dict(test_data_4, complex_rule)) # 输出 True
test_data_5 = {"price": 150, "stock": 5}
print(validate_dict(test_data_5, complex_rule)) # 输出 False
优化与扩展方向
上述方案已经满足大部分基础场景,还可以根据实际需求做进一步优化:
- 增加更多比较运算符,比如字符串匹配、正则校验等能力
- 添加规则缓存机制,避免重复解析相同规则
- 支持字段路径语法,比如校验嵌套字典的
user.address.city字段 - 增加详细的校验失败原因返回,方便排查问题
整个方案通过结构化规则定义和异常兜底,既保证了校验的灵活性,也避免了无效规则导致的程序崩溃,能够安全高效地完成字典键值对的复合条件验证。