Python含字符串列表的自定义类如何简化实现忽略顺序的__eq__比较方法
简便实现__eq__的三种可选方案
核心思路:避免手动枚举每个属性,通过通用逻辑处理列表的无序比较,适配属性扩展的场景。
方案1:全量列表自动无序比较(最简适配多属性场景)
直接通过dataclass内置的fields()遍历所有类字段,对所有列表类型自动排序后比较,其余类型直接比对值,新增属性无需修改__eq__逻辑。
代码示例:
from dataclasses import dataclass, fields from typing import List json_one = {"var_one": "hello", "var_two": ["foo", "bar"]} json_two = {"var_one": "hello", "var_two": ["bar", "foo"]} @dataclass class Test: var_one: str var_two: List[str] # 后续新增任意属性都不用调整__eq__代码 def __eq__(self, other): if not isinstance(other, Test): return False for field in fields(self): self_val = getattr(self, field.name) other_val = getattr(other, field.name) if isinstance(self_val, list) and isinstance(other_val, list): if sorted(self_val) != sorted(other_val): return False else: if self_val != other_val: return False return True test_one = Test(**json_one) test_two = Test(**json_two) print(test_one == test_two) # 输出True
适用场景
所有列表属性都需要无序比较,没有保序比较需求的场景。
注意
如果列表元素为不可排序类型会抛出异常,字符串、数字等可哈希可排序元素无影响。
方案2:标记式无序比较(灵活适配混合需求)
如果部分列表需要保序比较、部分需要无序比较,可以通过字段元数据标记需要无序比较的列表,__eq__逻辑只对标记字段做排序处理。
代码示例:
from dataclasses import dataclass, fields, field from typing import List @dataclass class Test: var_one: str # 标记该字段需要无序比较 var_two: List[str] = field(metadata={"unordered_compare": True}) # 未标记的列表默认按原顺序比较 ordered_var: List[int] def __eq__(self, other): if not isinstance(other, Test): return False for f in fields(self): self_val = getattr(self, f.name) other_val = getattr(other, f.name) if f.metadata.get("unordered_compare") and isinstance(self_val, list) and isinstance(other_val, list): if sorted(self_val) != sorted(other_val): return False else: if self_val != other_val: return False return True
适用场景
同时存在有序、无序列表比较需求的场景,扩展性更强。
方案3:自定义无序列表类型(完全不用写__eq__)
自定义继承自list的类型,重写其__eq__方法实现自动排序比较,直接用dataclass默认生成的__eq__即可满足需求。
代码示例:
from dataclasses import dataclass from typing import List class UnorderedList(list): def __eq__(self, other): if isinstance(other, list): return sorted(self) == sorted(other) return super().__eq__(other) json_one = {"var_one": "hello", "var_two": ["foo", "bar"]} json_two = {"var_one": "hello", "var_two": ["bar", "foo"]} @dataclass class Test: var_one: str var_two: UnorderedList # 无需自定义__eq__,用默认生成的即可 # 加载JSON时转换对应字段即可 test_one = Test(var_one=json_one["var_one"], var_two=UnorderedList(json_one["var_two"])) test_two = Test(var_one=json_two["var_one"], var_two=UnorderedList(json_two["var_two"])) print(test_one == test_two) # 输出True
适用场景
无序列表字段较多,不想维护自定义__eq__逻辑的场景。
注意
如果是通过JSON序列化库加载数据,可以配置序列化钩子自动将对应列表转成UnorderedList,无需手动转换。
通用注意事项
所有方案都优先用sorted()而非set()做比较,避免列表存在重复元素时出现判断错误(比如["a","a"]和["a"]用set比较会误判为相等)。
内容的提问来源于stack exchange,提问作者Kinder9211
相关产品推荐
相关产品推荐

