Complete guide to Python's __ne__ method covering inequality comparison, operator overloading, and custom implementations.
Last modified April 8, 2025
This comprehensive guide explores Python’s ne method, the special method that implements the “not equal” comparison operation. We’ll cover basic usage, relationship with eq, and practical examples.
The ne method is called when using the != operator. It should return True if objects are not equal, False otherwise. By default, it delegates to eq and negates the result.
Key characteristics: it must accept two parameters (self and other), should return a boolean value, and should implement consistent behavior with eq. It’s part of Python’s rich comparison methods.
Here’s a simple class implementing both eq and ne to demonstrate their relationship. The class represents a point in 2D space.
basic_ne.py
class Point: def init(self, x, y): self.x = x self.y = y
def __eq__(self, other):
if not isinstance(other, Point):
return NotImplemented
return self.x == other.x and self.y == other.y
def __ne__(self, other):
return not (self == other)
p1 = Point(1, 2) p2 = Point(1, 2) p3 = Point(3, 4)
print(p1 != p2) # False print(p1 != p3) # True
This example shows the standard pattern where ne is implemented by negating eq. This ensures consistent behavior between equality and inequality comparisons.
The NotImplemented return in eq tells Python to try the comparison the other way around or fall back to default behavior if the types are incompatible.
Sometimes you might need custom inequality logic that isn’t simply the negation of equality. Here’s an example with a versioned document class.
custom_ne.py
class Document: def init(self, content, version): self.content = content self.version = version
def __eq__(self, other):
if not isinstance(other, Document):
return NotImplemented
return self.content == other.content
def __ne__(self, other):
if not isinstance(other, Document):
return NotImplemented
# Documents are unequal if content differs OR versions differ
return self.content != other.content or self.version != other.version
doc1 = Document(“Hello”, 1.0) doc2 = Document(“Hello”, 1.1) doc3 = Document(“World”, 1.0)
print(doc1 != doc2) # True (versions differ) print(doc1 != doc3) # True (content differs)
In this case, documents are considered equal if their content matches, but unequal if either content or version differs. This shows how ne can implement more complex logic than just negating eq.
This pattern might be useful when you want to track changes but consider some attributes as metadata that shouldn’t affect equality comparisons.
When working with inheritance, you need to ensure ne behaves correctly with parent and child classes. Here’s an example demonstrating this.
inheritance_ne.py
class Animal: def init(self, name): self.name = name
def __eq__(self, other):
if not isinstance(other, Animal):
return NotImplemented
return self.name == other.name
def __ne__(self, other):
return not (self == other)
class Dog(Animal): def init(self, name, breed): super().init(name) self.breed = breed
def __eq__(self, other):
if not isinstance(other, Dog):
return NotImplemented
return super().__eq__(other) and self.breed == other.breed
animal = Animal(“Buddy”) dog1 = Dog(“Buddy”, “Labrador”) dog2 = Dog(“Buddy”, “Poodle”)
print(animal != dog1) # True (different types) print(dog1 != dog2) # True (different breeds)
This example shows how inequality works with inheritance. The Animal class implements basic equality/inequality by name, while Dog adds breed comparison. The ne method in the parent works for both.
Note that animal != dog1 returns True because they’re different types, even though they share the same name. This demonstrates type checking in comparison methods.
The ne method should properly handle comparisons with different types. Here’s an example with a class that can compare with integers.
different_types.py
class RomanNumeral: def init(self, value): self.value = value
def __eq__(self, other):
if isinstance(other, RomanNumeral):
return self.value == other.value
if isinstance(other, int):
return self.value == other
return NotImplemented
def __ne__(self, other):
eq_result = self.__eq__(other)
if eq_result is NotImplemented:
return NotImplemented
return not eq_result
num1 = RomanNumeral(5) num2 = RomanNumeral(5) num3 = RomanNumeral(7)
print(num1 != num2) # False print(num1 != num3) # True print(num1 != 5) # False print(num1 != 10) # True print(num1 != “V”) # True (falls back to default behavior)
This RomanNumeral class can compare both with other instances and with integers. The ne method properly handles all cases by delegating to eq and negating its result.
When comparing with incompatible types (“V” string), it returns NotImplemented, allowing Python to try the reverse operation or use default behavior.
For complex objects, you might optimize ne by checking for inequality early rather than always computing full equality first.
optimized_ne.py
class Vector: def init(self, x, y, z): self.x = x self.y = y self.z = z
def __eq__(self, other):
if not isinstance(other, Vector):
return NotImplemented
return self.x == other.x and self.y == other.y and self.z == other.z
def __ne__(self, other):
if not isinstance(other, Vector):
return NotImplemented
# Early exit if any component differs
if self.x != other.x:
return True
if self.y != other.y:
return True
if self.z != other.z:
return True
return False
v1 = Vector(1, 2, 3) v2 = Vector(1, 2, 3) v3 = Vector(1, 0, 3)
print(v1 != v2) # False print(v1 != v3) # True
This optimized ne implementation checks components one by one, returning True as soon as it finds any difference. For large objects where equality is expensive to compute, this can improve performance.
The optimization is most beneficial when inequality is the common case, as it allows early exit from the comparison. For equal objects, it performs the same work as eq.
Maintain consistency with eq: Ensure a == b implies not (a != b)
Handle different types properly: Return NotImplemented for unsupported types
Consider performance: Optimize ne if inequality checks are frequent
Document behavior: Clearly document any special comparison logic
Test thoroughly: Test edge cases including different types and inheritance
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.