You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过重写__eq__和__hash__优雅实现dataclass实例的灵活属性过滤?

灵活过滤Person实例列表的实现思路

一、直接过滤:列表推导式(最直观)

不需要修改Person类,直接根据目标属性写过滤逻辑,代码简洁直接:

  • 筛选生日为June的实例:
june_people = [p for p in persons if p.birthday == 'June']
  • 筛选名字为Max的实例:
max_people = [p for p in persons if p.name == 'Max']
  • 支持复杂条件,比如名字长度大于3:
long_name_people = [p for p in persons if len(p.name) > 3]

二、通用过滤函数(提升复用性)

如果需要多次基于不同属性或条件过滤,可以封装通用函数:

按属性值精确匹配

def filter_by_attribute(items, attr_name, target_value):
    return [item for item in items if getattr(item, attr_name) == target_value]

# 使用示例
alice_people = filter_by_attribute(persons, 'name', 'Alice')
august_people = filter_by_attribute(persons, 'birthday', 'August')

支持自定义条件

如果需要大于、包含等复杂判断,可扩展为接受判断函数:

def filter_by_condition(items, condition):
    return [item for item in items if condition(item)]

# 示例:筛选生日在上半年的实例
first_half_months = ['January', 'February', 'March', 'April', 'May', 'June']
first_half_people = filter_by_condition(persons, lambda p: p.birthday in first_half_months)

三、重写__eq__和__hash__的适用场景

重写这两个方法主要用于实例相等性判断或哈希容器去重/分组,而非通用过滤。如果需要固定按某个属性判断实例相等,可以这么写:

from dataclasses import dataclass

@dataclass
class Person:
    name: str
    birthday: str

    def __eq__(self, other):
        if not isinstance(other, Person):
            return False
        return self.name == other.name  # 仅以name判断相等

    def __hash__(self):
        return hash(self.name)  # 哈希值与name绑定,和__eq__逻辑一致

此时可以用集合快速去重同名实例:

unique_name_persons = list(set(persons))

注意:__eq__和__hash__的逻辑必须一致,否则会导致哈希容器(如set、dict)行为异常。如果需要灵活切换判断属性,这种固定重写的方式不如直接用过滤函数。

四、进阶:按属性分组(itertools.groupby)

如果需要将实例按属性分组(比如把所有同名/同生日的实例归为一组),可以用itertools.groupby:

from itertools import groupby
from operator import attrgetter

# 按name分组:需先按name排序
persons_sorted_by_name = sorted(persons, key=attrgetter('name'))
name_groups = {name: list(group) for name, group in groupby(persons_sorted_by_name, key=attrgetter('name'))}

# 按birthday分组
persons_sorted_by_bday = sorted(persons, key=attrgetter('birthday'))
bday_groups = {bday: list(group) for bday, group in groupby(persons_sorted_by_bday, key=attrgetter('birthday'))}

# 示例:获取所有叫Alice的实例
alice_group = name_groups.get('Alice', [])

内容的提问来源于stack exchange,提问作者Jailbone

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 04:55:18