Python language basics 27: value and reference equality basics
July 5, 2015 Leave a comment
Introduction
In the previous post we started discussing the most important cornerstone of object-oriented languages, i.e. objects. We saw how every variable assignment created an object reference in memory with a key, a value and a pointer which points from the key to the value. We also discussed what happens in memory when assigning a value to a variable.
In this post we’ll go through the absolute basics of equality in Python. The notions of value and reference equality are closely related to objects.
Value equality
Value equality is, as its name implies, based on values. Value equality is tested by the ‘==’ operator:
x = 5 y = 5 print(x == y)
This prints “True” as x and y have the same value, i.e. they point to the same value in the heap in memory.
The same works for strings:
s1 = 'hello' s2 = 'hello' print(s1 == s2)
This also prints “True” as s1 and s2 point to the same character sequence created in the heap. However, keep in mind that string value comparison is case sensitive so the following evaluates till false:
s1 = 'Hello' s2 = 'hello' print(s1 == s2)
Value equality in the above cases is easy. 5 = 5 and “hello” = “hello”, those are straightforward comparison cases. Most popular programming languages will be able to handle and evaluate those without any difficulty. Python will “know” how to determine whether two numbers or two strings are equal. The ‘==’ operator can work for the built-in collection types we’ve seen so far:
myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"} mySecondDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"} print(myFirstDictionary == mySecondDictionary)
myFirstList = ["small", "medium", "large", "x-large"] mySecondList = ["small", "medium", "large", "x-large"] print(myFirstList == mySecondList)
Both print statements will print “True” as the two dictionary and the two list objects respectively are equal, i.e. they have the same values.
Value equality is not always as well-defined. We’ll come back to this topic later on when we discuss how we can construct our own custom objects.
Reference equality
Reference equality means equality based on pointers, i.e. whether two keys on the stack point to the same value on the heap. Reference equality is tested through the ‘is’ operator:
x = 5 y = 5 print(x is y) s1 = 'hello' s2 = 'hello' print(s1 is s2)
Both ‘is’ statements resolve to true. ‘x’ and ‘y’ point to the same integer value 5, s1 and s2 point to the same string value ‘hello’, therefore they reference the same values.
However, consider the following examples:
myFirstDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"} mySecondDictionary = {"S": "Small", "M": "Medium", "L": "Large", "XL": "X-Large"} print(myFirstDictionary is mySecondDictionary) myFirstList = ["small", "medium", "large", "x-large"] mySecondList = ["small", "medium", "large", "x-large"] print(myFirstList is mySecondList)
Both ‘is’ statements will evaluate to False. myFirstDictionary and mySecondDictionary will each point to separate values in memory. Their values are equal as we saw above but Python creates two separate entries on the heap. The same analogy is true for the list types.
We’ve seen that “everything is an object” in Python. Still, we’ve found a fundamental difference between how primitive type objects – also called value types – like numbers and strings and reference types such as dictionaries, lists and as we’ll see later your custom objects are handled in memory. We’ll explore one more interesting facet of equality in the next post.
Read all Python-related posts on this blog here.