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

Python通用__eq__()方法实现:新增属性无需修改方法

Creating a Generic __eq__ Method with Comprehensions

Great question! This is exactly the kind of problem where Python's introspection tools and comprehensions shine—you can absolutely build a maintainable, attribute-agnostic __eq__ method that doesn't need updates when you add new fields like nick.

The Catch with Raw dir()

First, a quick heads-up: dir() returns all attributes of an object, including built-in magic methods/properties (like __init__, __class__) that you don't want to compare. So we need to filter those out, and comprehensions are perfect for that clean, concise filtering.

Solution 1: List Comprehensions with Filtered dir()

Here's how you can use a list comprehension to grab only non-magic attributes, then compare them between instances:

class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

    def __eq__(self, other):
        # First, ensure we're comparing instances of the same class
        if not isinstance(other, type(self)):
            return False
        
        # Use a list comprehension to exclude magic attributes (starts/ends with __)
        self_public_attrs = [attr for attr in dir(self) if not (attr.startswith('__') and attr.endswith('__'))]
        other_public_attrs = [attr for attr in dir(other) if not (attr.startswith('__') and attr.endswith('__'))]

        # Check if both instances have matching attribute sets (sorted to avoid order issues)
        if sorted(self_public_attrs) != sorted(other_public_attrs):
            return False
        
        # Use a generator expression to compare each attribute's value efficiently
        return all(getattr(self, attr) == getattr(other, attr) for attr in self_public_attrs)

Solution 2: More Precision with __dict__

If your class doesn't use __slots__, self.__dict__ stores exactly the instance's custom attributes (no magic stuff included). This is more efficient and targeted than dir():

class User:
    def __init__(self, name, email):
        self.name = name
        self.email = email

    def __eq__(self, other):
        if not isinstance(other, type(self)):
            return False
        
        # Grab all custom attribute keys with a list comprehension
        self_attr_keys = [key for key in self.__dict__.keys()]
        
        # Verify attribute keys match, then compare values
        return (self_attr_keys == list(other.__dict__.keys()) and
                all(getattr(self, key) == getattr(other, key) for key in self_attr_keys))

Handling __slots__

If you use __slots__ for memory optimization, your class won't have a __dict__. Instead, you can directly iterate over __slots__ with a comprehension:

class UserWithSlots:
    __slots__ = ('name', 'email', 'nick')
    def __init__(self, name, email, nick=None):
        self.name = name
        self.email = email
        self.nick = nick

    def __eq__(self, other):
        if not isinstance(other, type(self)):
            return False
        
        # Use a generator expression to compare all slot-defined attributes
        return all(getattr(self, slot) == getattr(other, slot) for slot in self.__slots__)

Key Takeaways

  • Always start with a type check: comparing instances of different classes should return False (adjust only if you intend cross-class equality).
  • Sorting attribute lists (like in Solution 1) ensures attribute order doesn't break equality checks.
  • Generator expressions (used in all() calls) are memory-efficient—they don't create a full list of comparisons upfront.

This approach means whenever you add a new attribute (like nick), you don't need to touch the __eq__ method at all—it'll automatically include the new field in comparisons.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:09:32