Comparing two objects of the same class
Often you want to compare two objects of the same kind: is this parcel heavier than that one? Is this runner faster? You could write a function that takes both objects:
def heavier(first, second):
return first.weight > second.weight
In object-oriented programming, though, the code that works on parcels belongs in the Parcel class, as a method. A method can take another object of its own class as a parameter. Then one parcel is self, the one the method is called on, and the other is the parameter, often called other:
class Parcel:
def __init__(self, label, weight):
self.label = label
self.weight = weight
def heavier_than(self, other):
return self.weight > other.weight
books = Parcel("books", 12)
pillow = Parcel("pillow", 2)
if books.heavier_than(pillow):
print(f"The {books.label} parcel is heavier than the {pillow.label} parcel")
print(pillow.heavier_than(books))
The books parcel is heavier than the pillow parcel
FalseIn books.heavier_than(pillow), the object to the left of the dot (books) is self inside the method, and the object in the parentheses (pillow) is other. Swap them and you ask the opposite question.
The method returns the comparison itself. self.weight > other.weight is already True or False, so there's no need for an if that returns True in one branch and False in the other.
If you write type hints, the hint for other is the class's own name: def heavier_than(self, other: "Parcel"):. Many programs put it in quotes, because older versions of Python read the hint before the class was finished and didn't know the name yet. Python 3.14, which runs your code on this site, accepts it with or without the quotes.
Helper variables: self or no self?
Sometimes a method needs a few values only while it works. As you have seen with helper methods, those are local variables, written without self.:
class Order:
def __init__(self, item, unit_price, quantity):
self.item = item
self.unit_price = unit_price
self.quantity = quantity
def costs_more_than(self, other):
my_total = self.unit_price * self.quantity
other_total = other.unit_price * other.quantity
return my_total > other_total
pens = Order("pens", 2, 30)
paper = Order("paper", 7, 5)
print(pens.costs_more_than(paper))
print(paper.costs_more_than(pens))
True
Falsemy_total and other_total disappear when the method ends, which is what you want. Writing self.my_total = ... would work too, but it would quietly add a new attribute to the object that stays there after the method is done. Other methods could then use it by accident, and some objects would have the attribute while others wouldn't, depending on which methods happened to run. Keep the rule simple: an attribute (self.) is something the object has to remember; a helper variable is scratch paper for one method.