7.6 Comparisons, Equality, and Truth

All 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:

  • The == operator tests value equivalence. Python performs an equivalence test, comparing all nested objects recursively

  • The is operator tests object identity. Python tests whether the two are really the same object (i.e., live at the same address in memory).

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:

  • Numbers are true if nonzero.

  • Other objects are true if nonempty.

Table 7-4 gives examples of true and false objects in Python.

Table 7-4. Example object truth values

Object

Value

"spam"

True

""

False

[ ]

False

{ }

False

1

True

0.0

False

None

False

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, . . . ]

The New Boolean Type in 2.3

Python 2.3 introduces a new explicit Boolean data type called bool, with values True and False available as new preassigned built-in names. Because of the way this new type is implemented, this is really just a minor extension to the notions of true and false outlined in this chapter, designed to make truth values more explicit. Most programmers were preassigning True and False to 1 and 0 anyway, so the new type makes this a standard. For instance, an infinite loop can now be coded as while True: instead of the less intuitive while 1:. Similarly, flags can be initialized with flag = False.

Internally, the new names True and False are instances of bool, which is in turn just a subclass of the built-in integer data type int. True and False behave exactly like integers 1 and 0, except that they have customized printing logic they print themselves as the words True and False, instead of the digits 1 and 0 (technically, bool redefines its str and repr string formats.) Because of this customization, the output of Boolean expressions typed at the interactive prompt print as the words True and False as of Python 2.3, instead of the 1 and 0 you see in this book.

For all other practical purposes, you can treat True and False as though they are predefined variables set to integer 1 and 0 (e.g., True + 3 yields 4). In truth tests, True and False evaluate to true and false, because they truly are just specialized versions of integers 1 and 0. Moreover, you are not required to use only Boolean types in if statements; all objects are still inherently true or false, and all the Boolean concepts mentioned in this chapter still work as before. More on Booleans in Chapter 9.


In general, Python compares types as follows:

  • Numbers are compared by relative magnitude.

  • Strings are compared lexicographically, character-by-character ("abc" < "ac").

  • Lists and tuples are compared by comparing each component, from left to right.

  • Dictionaries are compared as though comparing sorted (key, value) lists.

In later chapters, we'll see other object types that can change the way they get compared.



Learning Python
Learning Python: Powerful Object-Oriented Programming
ISBN: 0596158068
EAN: 2147483647
Year: 2003
Pages: 253
Authors: Mark Lutz

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net