According to the object.__eq__()
documentation, the default (that is, in the object
class) implementation for ==
is as follows:
True
if x is y
else NotImplemented
Now, the following code prints False
and True
in python 3.9:
class A:
pass
print(A() == A())
print(bool(NotImplemented))
No Comments on Where is the default behavior for object equality (`==`) defined? ,According to the object.__eq__() documentation, the default (that is, in the object class) implementation for == is as follows:,So my question is the following: where does the documentation mention the special behavior of NotImplemented in the context of __eq__ ?,Still following the documentation for NotImplemented, I inferred that NotImplemented implies that the Python runtime will try the comparison the other way around. That is try y.__eq__(x) if x.__eq__(y) returns NotImplemented (in the case of the == operator).
According to the object.__eq__()
documentation, the default (that is, in the object
class) implementation for ==
is as follows:
True
if x is y
else NotImplemented
Now, the following code prints False
and True
in python 3.9:
class A:
pass
print(A() == A())
print(bool(NotImplemented))
06/21/2022
The preceding example code may not handle every inheritance scenario the way you expect. Consider the following code:
TwoDPoint p1 = new ThreeDPoint(1, 2, 3);
TwoDPoint p2 = new ThreeDPoint(1, 2, 4);
Console.WriteLine(p1.Equals(p2)); // output: True
The preceding example code may not handle every inheritance scenario the way you expect. Consider the following code:
TwoDPoint p1 = new ThreeDPoint(1, 2, 3);
TwoDPoint p2 = new ThreeDPoint(1, 2, 4);
Console.WriteLine(p1.Equals(p2)); // output: True
The default behavior for these two methods gives answers that work only for simple cases. The equals() method returns true only when it is being compared to itself (i.e., the identity check). The hashCode() method returns an int based on a unique instance hash (such as the object's location in memory and may be calculated differently for different VM implementations).,The code above shows a simple example of an equals() method. Note that only the two non-static and non-transient fields (x and y) are being compared; the others (distance and version) are not relevant to instance-based comparison.,Each of these methods has a sensible default behavior that can be overridden in the subclasses (except for final methods, marked above with F). This article discusses overriding the equals() and hashCode() methods for data objects.,Fortunately, it is fairly easy to write a method that has this behavior. The equals method should compare:
public boolean equals(Object)
public class Point {
private static double version = 1.0;
private transient double distance;
private int x, y;
public boolean equals(Object other) {
if (other == this) return true;
if (other == null) return false;
if (getClass() != other.getClass()) return false;
Point point = (Point) other;
return (x == point.x && y == point.y);
}
}
Here's an example of a Person
class that performs equality checking on two reference types, name and birth:
public class Person {
private String name;
private Date birth;
public boolean equals(Object other) {
if (other == this) return true;
if (other == null) return false;
if (getClass() != other.getClass()) return false;
Person person = (Person) other;
return (
(name == person.name ||
(name != null && name.equals(person.name))) &&
(birth == person.birth ||
(birth != null && birth.equals(person.birth)))
);
}
}
We can improve on our hash function by using other variables in the hash computation:
public class Point {
private int x, y;
public boolean equals(Object other) {
...
}
public int hashCode() {
return x + y;
}
}
We can now add a hashCode()
method to the Point
class:
public class Point {
private int x, y;
public boolean equals(Object other) {
...
}
public int hashCode() {
return x * 31 ^ y * 37;
}
}
In other words, the default meaning of equals() is the same as referential equality. For immutable data types, this is almost always wrong. So you have to override the equals() method, replacing it with your own implementation.,Reference equality is the basis for equality in mutable data types; this is the only way to ensure consistency over time and avoid breaking rep invariants of hash tables.,For mutable objects, it’s tempting to implement strict observational equality. Java uses observational equality for most of its mutable data types, in fact. If two distinct List objects contain the same sequence of elements, then equals() reports that they are equal. ,Ready for change. Correctly-implemented equality for immutable types separates equality of reference from equality of abstract value, hiding from clients our decisions about whether values are shared. Choosing behavioral rather than observational equality for mutable types helps avoid unexpected aliasing bugs.
Here’s a simple example of an immutable ADT.
public class Duration {
private final int mins;
private final int secs;
// rep invariant:
// mins >= 0, secs >= 0
// abstraction function:
// represents a span of time of mins minutes and secs seconds
/** Make a duration lasting for m minutes and s seconds. */
public Duration(int m, int s) {
mins = m;
secs = s;
}
/** @return length of this duration in seconds */
public long getLength() {
return mins * 60 + secs;
}
}
Now which of the following values should be considered equal?
Duration d1 = new Duration(1, 2);
Duration d2 = new Duration(1, 3);
Duration d3 = new Duration(0, 62);
Duration d4 = new Duration(1, 2);
The equals()
method is defined by Object
, and its default implementation looks like this:
public class Object {
...
public boolean equals(Object that) {
return this == that;
}
}
Here’s our first try for Duration
:
public class Duration {
...
// Problematic definition of equals()
public boolean equals(Duration that) {
return this.getLength() == that.getLength();
}
}
There’s a subtle problem here. Why doesn’t this work? Let’s try this code:
Duration d1 = new Duration(1, 2);
Duration d2 = new Duration(1, 2);
Object o2 = d2;
d1.equals(d2)→ true
d1.equals(o2)→ false
So here’s the right way to implement Duration
’s equals()
method:
@Override
public boolean equals(Object thatObject) {
if (!(thatObject instanceof Duration)) return false;
Duration thatDuration = (Duration) thatObject;
return this.getLength() == thatDuration.getLength();
}
This fixes the problem:
Duration d1 = new Duration(1, 2);
Duration d2 = new Duration(1, 2);
Object o2 = d2;
d1.equals(d2)→ true
d1.equals(o2)→ true
Here’s an example of how an innocent attempt to make equality more flexible can go wrong. Suppose we wanted to allow for a tolerance in comparing Duration
objects, because different computers may have slightly unsynchronized clocks:
private static final int CLOCK_SKEW = 5; // seconds
@Override
public boolean equals(Object thatObject) {
if (!(thatObject instanceof Duration)) return false;
Duration thatDuration = (Duration) thatObject;
return Math.abs(this.getLength() - thatDuration.getLength()) <= CLOCK_SKEW;
}
Consider the latest implementation of Duration
in the reading, reprinted here for convenience:
public class Duration {
private final int mins;
private final int secs;
// rep invariant:
// mins >= 0, secs >= 0
// abstraction function:
// represents a span of time of mins minutes and secs seconds
/** Make a duration lasting for m minutes and s seconds. */
public Duration(int m, int s) {
mins = m;
secs = s;
}
/** @return length of this duration in seconds */
public long getLength() {
return mins * 60 + secs;
}
private static final int CLOCK_SKEW = 5; // seconds
@Override
public boolean equals(Object thatObject) {
if (!(thatObject instanceof Duration)) return false;
Duration thatDuration = (Duration) thatObject;
return Math.abs(this.getLength() - thatDuration.getLength()) <= CLOCK_SKEW;
}
}
Suppose these Duration
objects are created:
Duration d_0_60 = new Duration(0, 60);
Duration d_1_00 = new Duration(1, 0);
Duration d_0_57 = new Duration(0, 57);
Duration d_1_03 = new Duration(1, 3);
Consider the latest implementation of Duration
in the reading, reprinted here for convenience:
public class Duration {
private final int mins;
private final int secs;
// rep invariant:
// mins >= 0, secs >= 0
// abstraction function:
// represents a span of time of mins minutes and secs seconds
/** Make a duration lasting for m minutes and s seconds. */
public Duration(int m, int s) {
mins = m;
secs = s;
}
/** @return length of this duration in seconds */
public long getLength() {
return mins * 60 + secs;
}
private static final int CLOCK_SKEW = 5; // seconds
@Override
public boolean equals(Object thatObject) {
if (!(thatObject instanceof Duration)) return false;
Duration thatDuration = (Duration) thatObject;
return Math.abs(this.getLength() - thatDuration.getLength()) <= CLOCK_SKEW;
}
}
Suppose these Duration
objects are created:
Duration d_0_60 = new Duration(0, 60);
Duration d_1_00 = new Duration(1, 0);
Duration d_0_57 = new Duration(0, 57);
Duration d_1_03 = new Duration(1, 3);
Object
’s default hashCode()
implementation is consistent with its default equals()
:
public class Object {
...
public boolean equals(Object that) {
return this == that;
}
public int hashCode() {
return /* the memory address of this */;
}
}
But immutable objects need a different implementation of hashCode()
. For Duration
, since we haven’t overridden the default hashCode()
yet, we’re currently breaking the Object
contract:
Duration d1 = new Duration(1, 2);
Duration d2 = new Duration(1, 2);
d1.equals(d2)→ true
d1.hashCode()→ 2392
d2.hashCode()→ 4823
The standard way to construct a more reasonable hash code that still satisfies the contract is to compute a hash code for each component of the object that is used in the determination of equality (usually by calling the hashCode
method of each component), and then combining these, throwing in a few arithmetic operations. For Duration
, this is easy, because the abstract value of the class is already an integer value:
@Override
public int hashCode() {
return (int) getLength();
}
Consider the following ADT class:
class Person {
private String firstName;
private String lastName;
...
public boolean equals(Object obj) {
if (!(obj instanceof Person)) return false;
Person that = (Person) obj;
return this.lastName.toUpperCase().equals(that.lastName.toUpperCase());
}
public int hashCode() {
// TODO
}
}
Last Updated : 14 Aug, 2021,GATE CS 2021 Syllabus
Output:
true
false
false
Output:
Both Objects are equal.
Python automatically calls the __eq__ method of a class when you use the == operator to compare the instances of the class. By default, Python uses the is operator if you don’t provide a specific implementation for the __eq__ method.,Summary: in this tutorial, you’ll learn how to use the Python __eq__ method to compare two objects by their values.,To fix this, you can modify the __eq__ method to check if the object is an instance of the Person class before accessing the age attribute.,If the other object isn’t an instance of the Person class, the __eq__ method returns False, like this:
Suppose that you have the following Person
class with three instance attributes: first_name
, last_name
, and age
:
.wp - block - code {
border: 0;
padding: 0;
}
.wp - block - code > div {
overflow: auto;
}
.shcb - language {
border: 0;
clip: rect(1 px, 1 px, 1 px, 1 px); -
webkit - clip - path: inset(50 % );
clip - path: inset(50 % );
height: 1 px;
margin: -1 px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1 px;
word - wrap: normal;
word - break: normal;
}
.hljs {
box - sizing: border - box;
}
.hljs.shcb - code - table {
display: table;
width: 100 % ;
}
.hljs.shcb - code - table > .shcb - loc {
color: inherit;
display: table - row;
width: 100 % ;
}
.hljs.shcb - code - table.shcb - loc > span {
display: table - cell;
}
.wp - block - code code.hljs: not(.shcb - wrap - lines) {
white - space: pre;
}
.wp - block - code code.hljs.shcb - wrap - lines {
white - space: pre - wrap;
}
.hljs.shcb - line - numbers {
border - spacing: 0;
counter - reset: line;
}
.hljs.shcb - line - numbers > .shcb - loc {
counter - increment: line;
}
.hljs.shcb - line - numbers.shcb - loc > span {
padding - left: 0.75 em;
}
.hljs.shcb - line - numbers.shcb - loc::before {
border - right: 1 px solid #ddd;
content: counter(line);
display: table - cell;
padding: 0 0.75 em;
text - align: right; -
webkit - user - select: none; -
moz - user - select: none; -
ms - user - select: none;
user - select: none;
white - space: nowrap;
width: 1 % ;
}
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = ageCode language: Python(python)
And you create two instances of the Person
class:
john = Person('John', 'Doe', 25)
jane = Person('Jane', 'Doe', 25) Code language: Python(python)
In this example, the john
and jane
objects are not the same object. And you can check it using the is
operator:
print(john is jane) # FalseCode language: Python(python)
Since john
and jane
have the same age, you want them to be equal. In other words, you want the following expression to return True
:
john == jane
The following shows how to implement the __eq__
method in the Person
class that returns True
if two person objects have the same age:
class Person:
def __init__(self, first_name, last_name, age):
self.first_name = first_name
self.last_name = last_name
self.age = age
def __eq__(self, other):
return self.age == other.ageCode language: Python(python)