Object Oriented Programming: Comparing and inheritance
A summary from a course on datacamp.com:
When comparing two objects of a custom class using
==, Python by default compares just the object references, not the data contained in the objects. To override this behavior, the class can implement the special
__eq__() method, which accepts two arguments — the objects to be compared — and returns
False. This method will be implicitly called when two objects are compared.
BankAccount class from the previous chapter is available for you in the script pane. It has one attribute,
balance, and a
withdraw() method. Two bank accounts with the same balance are not necessarily the same account, but a bank account usually has an account number, and two accounts with the same account number should be considered the same.
Try selecting the code in lines 1-7 and pressing the “Run code” button. Then try to create a few
BankAccount objects in the console and compare them.
- Modify the
__init__()method to accept a new parameter –
number– and initialize a new
- Define an
__eq__()method that returns
numberattribute of two objects is equal.
- Examine the print statements and the output in the console.
__eq__()method should accept two arguments, usually called
- When adding parameters to
__init__(), remember that parameters without default values should be placed before parameters that have default values.
class BankAccount: # MODIFY to initialize a number attribute def __init__(self, number, balance=0): self.balance = balance self.number = number def withdraw(self, amount): self.balance -= amount # Define __eq__ that returns True if the number attributes are equal def __eq__(self, other): return self.number == other.number # Create accounts and compare them acct1 = BankAccount(123, 1000) acct2 = BankAccount(123, 1000) acct3 = BankAccount(456, 1000) print(acct1 == acct2) print(acct1 == acct3)
<script.py> output: True False
Notice that your method compares just the account numbers, but not balances. What would happen if two accounts have the same account number but different balances? The code you wrote will treat these accounts as equal, but it might be better to throw an error – an exception – instead, informing the user that something is wrong. At the end of the chapter, you’ll learn how to define your own exception classes to create these kinds of custom errors.
Checking class equality
In the previous exercise, you defined a
BankAccount class with a
numberattribute that was used for comparison. But if you were to compare a
BankAccount object to an object of another class that also has a
numberattribute, you could end up with unexpected results.
For example, consider two classes
acct == pn will return
True, even though we’re comparing a phone number with a bank account number.
It is good practice to check the class of objects passed to the
__eq__() method to make sure the comparison makes sense.
Phone and the
BankAccount classes have been defined. Try running the code as-is using the “Run code” button and examine the output.
- Modify the definition of
BankAccountto only return
numberattribute is the same and the
type()of both objects passed to it is the same.
Run the code and examine the output again
class BankAccount: def __init__(self, number, balance=0): self.number, self.balance = number, balance def withdraw(self, amount): self.balance -= amount # MODIFY to add a check for the type() def __eq__(self, other): return (self.number == other.number) acct = BankAccount(873555333) pn = Phone(873555333) print(acct == pn)
- __hash__() to use objects as dictionary keys and in sets
class BankAccount: def __init__(self, number, balance=0): self.number, self.balance = number, balance def withdraw(self, amount): self.balance -= amount # MODIFY to add a check for the type() def __eq__(self, other): return ((self.number == other.number) & (type(self) == type(other))) acct = BankAccount(873555333) pn = Phone(873555333) print(acct == pn)
<script.py> output: False
Now only comparing objects of the same class
BankAccount could return
True. Another way to ensure that an object has the same type as you expect is to use the
isinstance(obj, Class) function. This can helpful when handling inheritance, as Python considers an object to be an instance of both the parent and the child class.
pn == acct in the console (with reversed order of equality).
What does this tell you about the
Comparison and inheritance
What happens when an object is compared to an object of a child class? Consider the following two classes:
class Parent: def __eq__(self, other): print("Parent's __eq__() called") return True class Child(Parent): def __eq__(self, other): print("Child's __eq__() called") return True
Child class inherits from the
Parent class, and both implement the
__eq__() method that includes a diagnostic printout.
__eq__() method will be called when the following code is run?
p = Parent() c = Child() p == c
When ran in the console the result is:
Child's __eq__() called True
This shows that when two classes, one as the parent class containing an __eq__() method, and the same for the child case. And when both are turned into an object and the objects are compared, then Python always calls the child’s
__eq__()method when comparing a child object to a parent object.