Hi @dejong1968,
We have two different operations occuring here:
- creating two objects;
- comparing them for equality (and printing the result).
If the first case, the relevant operations are:
john = Person('john', 'doe', 25)
jane = Person('jane', 'doe', 25)
The two objects basically follow the same set of events.
- First, the interpreter finds the
Person
class, and calls its constructor with three arguments, the strings 'john'
(or 'jane'
), 'doe'
, and the integer 25
.
- If that succeeds, a new object (an instance of the Person class) is returned, and the interpreter assigns that to the variable named
john
(or jane
).
What do I mean by “constructor”?
The constructor is a special method, or in Python’s case, two methods, which are called to create a new instance of the class. Those two methods are the true constructor, the method called __new__
, and the “initalizer” __init__
.
The __new__
method actually creates the instance in memory; the __init__
method populates it with whatever data you need.
Don’t worry too much about the difference between them. Almost all classes will only use one or the other, and at this early stage in your journey to learn Python, you only need to care about __init__
.
So the constructor has created a Person
object, or instance, in memory. Now the __init__
method is automatically called to populate it with data.
This sets three attributes of the object. (Synonyms for “attribute” may include properties, members, or instance variables. None of those three are quite accurate for Python, so best to stick with attribute.)
self.first_name = first_name
Here, the variable self
represents the current instance being worked on. The part after the dot is the name of the attribute, “first_name”. So we are storing the value of the method parameter “first_name” into the object under the attribute name “first_name”.
And similarly for the other two attributes, “last_name” and “age”.
By the time the __init__
method runs, the instance has three attributes set, using “john”, “doe” and 25. That instance is then saved in the variable called john
.
Then the interpreter does it all again for the jane
variable.
Now we come to the second operation: comparing the john and jane variables for equality.
First the interpreter locates the objects stored in the variables, which both happen to be Person
objects. That will simplify matters.
The the interpreter will look for the special __eq__
method, used for implementing equality tests. It fetches that method by looking at the john
variable, so john is “self” and jane is “other”.
(Had you written jane == john
instead, then jane would be “self” and john “other”.)
Then the __eq__
method is executed. It ignores the first_name and last_name attributes, and only cares about the age attribute. If the two instances have the same age, then they are considered to be equal.
Earlier, I said that having both objects be Person
instances makes things simpler. What if they are different?
If the two objects are not from the same class, say you had a Person being compared with a Robot (say), the rules become more complicated. First the interpreter will ask the Person object if it knows how to compare itself to Robots; if it answers “no”, then the interpreter will try again by asking the Robot if it knows how to handle the equality test.
If that also fails, the interpreter will fall back on the ultimate test: it will check to see if the two arguments are the same object in memory, in which case they are equal, otherwise they are considered unequal.