[ Team LiB ] |
7.6 Comparisons, Equality, and TruthAll Python objects also respond to the comparisons: test for equality, relative magnitude, and so on. Python comparisons always inspect all parts of compound objects, until a result can be determined. In fact, when nested objects are present, Python automatically traverses data structures to apply comparisons recursively—left to right, and as deep as needed. For instance, a comparison of list objects compares all their components automatically: >>> L1 = [1, ('a', 3)] # Same value, unique objects >>> L2 = [1, ('a', 3)] >>> L1 == L2, L1 is L2 # Equivalent? Same object? (1, 0) Here, L1 and L2 are assigned lists that are equivalent, but distinct objects. Because of the nature of Python references (studied in Chapter 4), there are two ways to test for equality:
In the example, L1 and L2 pass the == test (they have equivalent values because all their components are equivalent), but fail the is check (they are two different objects, and hence two different pieces of memory). Notice what happens for short strings: >>> S1 = 'spam' >>> S2 = 'spam' >>> S1 == S2, S1 is S2 (1, 1) Here, we should have two distinct objects that happen to have the same value: == should be true, and is should be false. Because Python internally caches and reuses short strings as an optimization, there really is just a single string, 'spam', in memory, shared by S1 and S2; hence, the is identity test reports a true result. To trigger the normal behavior, we need to use longer strings that fall outside the cache mechanism: >>> S1 = 'a longer string' >>> S2 = 'a longer string' >>> S1 == S2, S1 is S2 (1, 0) Because strings are immutable, the object caching mechanism is irrelevent to your code—string can't be changed in-place, regardless of how many variables refer to them. If identity tests seem confusing, see Section 4.6 in Chapter 4 for a refresher on object reference concepts. As a rule of thumb, the == operator is what you will want to use for almost all equality checks; is is reserved for highly specialized roles. We'll see cases of both operators put to use later in the book. Notice that relative magnitude comparisons are also applied recursively to nested data structures: >>> L1 = [1, ('a', 3)] >>> L2 = [1, ('a', 2)] >>> L1 < L2, L1 == L2, L1 > L2 # less,equal,greater: tuple of results (0, 0, 1) Here, L1 is greater than L2 because the nested 3 is greater than 2. The result of the last line above is really a tuple of three objects—the results of the three expressions typed (an example of a tuple without its enclosing parentheses). The three values in this tuple represent true and false values; in Python, an integer 0 represents false and an integer 1 represents true. Python also recognizes any empty data structure as false, and any nonempty data structure as true. More generally, the notions of true and false are intrinsic properties of every object in Python—each object is true or false, as follows:
Table 7-4 gives examples of true and false objects in Python.
Python also provides a special object called None (the last item in Table 7-4), which is always considered to be false. None is the only value of a special data type in Python; it typically serves as an empty placeholder, much like a NULL pointer in C. For example, recall that for lists, you cannot assign to an offset unless that offset already exists (the list does not magically grow if you assign out of bounds). To preallocate a 100-item list such that you can add to any of the 100 offsets, you can fill one with None objects: >>> L = [None] * 100 >>> >>> L [None, None, None, None, None, None, None, . . . ]
In general, Python compares types as follows:
In later chapters, we'll see other object types that can change the way they get compared. |
[ Team LiB ] |