4.6. Standard Type Built-in FunctionsAlong with generic operators, which we have just seen, Python also provides some BIFs that can be applied to all the basic object types: cmp(),repr(),str(),type(), and the single reverse or back quotes (``) operator, which is functionally equivalent to repr().
4.6.1. type()We now formally introduce type(). In Python versions earlier than 2.2, type() is a BIF. Since that release, it has become a "factory function." We will discuss these later on in this chapter, but for now, you may continue to think of type() as a BIF. The syntax for type() is: type(object) In the examples above, we take an integer and a string and obtain their types using the type() BIF; in order to also verify that types themselves are types, we call type() on the output of a type() call. Note the interesting output from the type() function. It does not look like a typical Python data type, i.e., a number or string, but is something enclosed by greater-than and less-than signs. This syntax is generally a clue that what you are looking at is an object. Objects may implement a printable string representation; however, this is not always the case. In these scenarios where there is no easy way to "display" an object, Python "pretty-prints" a string representation of the object. The format is usually of the form: <object_something_or_another>. Any object displayed in this manner generally gives the object type, an object ID or location, or other pertinent information. 4.6.2. cmp()The cmp() BIF CoMPares two objects, say, obj1 and obj2, and returns a negative number (integer) if obj1 is less than obj2, a positive number if obj1 is greater than obj2, and zero if obj1 is equal to obj2. Notice the similarity in return values as C's strcmp(). The comparison used is the one that applies for that type of object, whether it be a standard type or a user-created class; if the latter, cmp() will call the class's special __cmp__() method. More on these special methods in Chapter 13, on Python classes. Here are some samples of using the cmp() BIF with numbers and strings. >>> a, b = -4, 12 We will look at using cmp() with other objects later. 4.6.3. str() and repr() (and `` Operator)The str() STRing and repr() REPResentation BIFs or the single back or reverse quote operator ( `` ) come in very handy if the need arises to either re-create an object through evaluation or obtain a human-readable view of the contents of objects, data values, object types, etc. To use these operations, a Python object is provided as an argument and some type of string representation of that object is returned. In the examples that follow, we take some random Python types and convert them to their string representations. >>> str(4.53-2j) Although all three are similar in nature and functionality, only repr() and `` do exactly the same thing, and using them will deliver the "official" string representation of an object that can be evaluated as a valid Python expression (using the eval() BIF). In contrast, str() has the job of delivering a "printable" string representation of an object, which may not necessarily be acceptable by eval(), but will look nice in a print statement. There is a caveat that while most return values from repr() can be evaluated, not all can: >>> eval(`type(type))`) The executive summary is that repr( ) is Python-friendly while str() produces human-friendly output. However, with that said, because both types of string representations coincide so often, on many occasions all three return the exact same string. Core Note: Why have both repr() and ``?
4.6.4. type() and isinstance()Python does not support method or function overloading, so you are responsible for any "introspection" of the objects that your functions are called with. (Also see the Python FAQ 4.75.) Fortunately, we have the type() BIF to help us with just that, introduced earlier in Section 4.3.1. What's in a name? Quite a lot, if it is the name of a type. It is often advantageous and/or necessary to base pending computation on the type of object that is received. Fortunately, Python provides a BIF just for that very purpose. type() returns the type for any Python object, not just the standard types. Using the interactive interpreter, let us take a look at some examples of what type() returns when we give it various objects. >>> type('') Types and classes were unified in Python 2.2. You will see output different from that above if you are using a version of Python older than 2.2: >>> type('') In addition to type(), there is another useful BIF called isinstance(). We cover it more formally in Chapter 13 (Object-Oriented Programming), but here we can introduce it to show you how you can use it to help determine the type of an object. ExampleWe present a script in Example 4.1 that shows how we can use isinstance() and type() in a runtime environment. We follow with a discussion of the use of type() and how we migrated to using isinstance() instead for the bulk of the work in this example. Example 4.1. Checking the Type (typechk.py)
The Evolution of This ExampleOriginalThe same function was defined quite differently in the first edition of this book: def displayNumType(num): As Python evolved in its slow and simple way, so must we. Take a look at our original conditional expression: if type(num) == type(0)... Reducing Number of Function CallsIf we take a closer look at our code, we see a pair of calls to type(). As you know, we pay a small price each time a function is called, so if we can reduce that number, it will help with performance. An alternative to comparing an object's type with a known object's type (as we did above and in the example below) is to utilize the types module, which we briefly mentioned earlier in the chapter. If we do that, then we can use the type object there without having to "calculate it." We can then change our code to only having one call to the type() function: >>> import types Object Value Comparison versus Object Identity ComparisonWe discussed object value comparison versus object identity comparison earlier in this chapter, and if you realize one key fact, then it will become clear that our code is still not optimal in terms of performance. During runtime, there is always only one type object that represents an integer. In other words, type(0), type(42), type(-100) are always the same object: <type 'int'> (and this is also the same object as types.IntType). If they are always the same object, then why do we have to compare their values since we already know they will be the same? We are "wasting time" extracting the values of both objects and comparing them if they are the same object, and it would be more optimal to just compare the objects themselves. Thus we have a migration of the code above to the following: if type(num) is types.IntType... # or type(0) Does that make sense? Object value comparison via the equal sign requires a comparison of their values, but we can bypass this check if the objects themselves are the same. If the objects are different, then we do not even need to check because that means the original variable must be of a different type (since there is only one object of each type). One call like this may not make a difference, but if there are many similar lines of code throughout your application, then it starts to add up. Reduce the Number of LookupsThis is a minor improvement to the previous example and really only makes a difference if your application performs makes many type comparisons like our example. To actually get the integer type object, the interpreter has to look up the types name first, and then within that module's dictionary, find IntType. By using from-import, you can take away one lookup: from types import IntType Convenience and StyleThe unification of types and classes in 2.2 has resulted in the expected rise in the use of the isinstance() BIF. We formally introduce isinstance() in Chapter 13 (Object-Oriented Programming), but we will give you a quick preview now. This Boolean function takes an object and one or more type objects and returns true if the object in question is an instance of one of the type objects. Since types and classes are now the same, int is now a type (object) and a class. We can use isinstance() with the built-in types to make our if statement more convenient and readable: if isinstance(num, int)... Using isinstance() along with type objects is now also the accepted style of usage when introspecting objects' types, which is how we finally arrive at our updated typechk.py application above. We also get the added bonus of isinstance() accepting a tuple of type objects to check against our object with instead of having an if-elif-else if we were to use only type(). 4.6.5. Python Type Operator and BIF SummaryA summary of operators and BIFs common to all basic Python types is given in Table 4.5. The progressing shaded groups indicate hierarchical precedence from highest-to-lowest order. Elements grouped with similar shading all have equal priority. Note that these (and most Python) operators are available as functions via the operator module.
|
Monday, October 19, 2009
Section 4.6. Standard Type Built-in Functions
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment