Python通用__eq__()方法实现:新增属性无需修改方法
__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

