Numbers in Action

On to the code! Probably the best way to understand numeric objects and expressions is to see them in action, so with those basics in hand let’s start up the interactive command line and try some simple but illustrative operations (be sure to see Chapter 3 for pointers if you need help starting an interactive session).

Variables and Basic Expressions

First of all, let’s exercise some basic math. In the following interaction, we first assign two variables (a and b) to integers so we can use them later in a larger expression. Variables are simply names—created by you or Python—that are used to keep track of information in your program. We’ll say more about this in the next chapter, but in Python:

  • Variables are created when they are first assigned values.

  • Variables are replaced with their values when used in expressions.

  • Variables must be assigned before they can be used in expressions.

  • Variables refer to objects and are never declared ahead of time.

In other words, these assignments cause the variables a and b to spring into existence automatically:

% python
>>> a = 3                  # Name created: not declared ahead of time
>>> b = 4

I’ve also used a comment here. Recall that in Python code, text after a # mark and continuing to the end of the line is considered to be a comment and is ignored by Python. Comments are a way to write human-readable documentation for your code, and an important part of programming. I’ve added them to most of this book’s examples to help explain the code. In the next part of the book, we’ll meet a related but more functional feature—documentation strings—that attaches the text of your comments to objects so it’s available after your code is loaded.

Because code you type interactively is temporary, though, you won’t normally write comments in this context. If you’re working along, this means you don’t need to type any of the comment text from the # through to the end of the line; it’s not a required part of the statements we’re running this way.

Now, let’s use our new integer objects in some expressions. At this point, the values of a and b are still 3 and 4, respectively. Variables like these are replaced with their values whenever they’re used inside an expression, and the expression results are echoed back immediately when we’re working interactively:

>>> a + 1, a − 1           # Addition (3 + 1), subtraction (3 − 1)
(4, 2)
>>> b * 3, b / 2           # Multiplication (4 * 3), division (4 / 2)
(12, 2.0)
>>> a % 2, b ** 2          # Modulus (remainder), power (4 ** 2)
(1, 16)
>>> 2 + 4.0, 2.0 ** b      # Mixed-type conversions
(6.0, 16.0)

Technically, the results being echoed back here are tuples of two values because the lines typed at the prompt contain two expressions separated by commas; that’s why the results are displayed in parentheses (more on tuples later). Note that the expressions work because the variables a and b within them have been assigned values. If you use a different variable that has not yet been assigned, Python reports an error rather than filling in some default value:

>>> c * 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'c' is not defined

You don’t need to predeclare variables in Python, but they must have been assigned at least once before you can use them. In practice, this means you have to initialize counters to zero before you can add to them, initialize lists to an empty list before you can append to them, and so on.

Here are two slightly larger expressions to illustrate operator grouping and more about conversions, and preview a difference in the division operator in Python 3.X and 2.X:

>>> b / 2 + a               # Same as ((4 / 2) + 3)   [use 2.0 in 2.X]
5.0
>>> b / (2.0 + a)           # Same as (4 / (2.0 + 3)) [use print before 2.7]
0.8

In the first expression, there are no parentheses, so Python automatically groups the components according to its precedence rules—because / is lower in Table 5-2 than +, it binds more tightly and so is evaluated first. The result is as if the expression had been organized with parentheses as shown in the comment to the right of the code.

Also, notice that all the numbers are integers in the first expression. Because of that, Python 2.X’s / performs integer division and addition and will give a result of 5, whereas Python 3.X’s / performs true division, which always retains fractional remainders and gives the result 5.0 shown. If you want 2.X’s integer division in 3.X, code this as b // 2 + a; if you want 3.X’s true division in 2.X, code this as b / 2.0 + a (more on division in a moment).

In the second expression, parentheses are added around the + part to force Python to evaluate it first (i.e., before the /). We also made one of the operands floating point by adding a decimal point: 2.0. Because of the mixed types, Python converts the integer referenced by a to a floating-point value (3.0) before performing the +. If instead all the numbers in this expression were integers, integer division (4 / 5) would yield the truncated integer 0 in Python 2.X but the floating point 0.8 shown in Python 3.X. Again, stay tuned for formal division details.

Numeric Display Formats

If you’re using Python 2.6, Python 3.0, or earlier, the result of the last of the preceding examples may look a bit odd the first time you see it:

>>> b / (2.0 + a)           # Pythons <= 2.6: echoes give more (or fewer) digits
0.80000000000000004

>>> print(b / (2.0 + a))    # But print rounds off digits
0.8

We met this phenomenon briefly in the prior chapter, and it’s not present in Pythons 2.7, 3.1, and later. The full story behind this odd result has to do with the limitations of floating-point hardware and its inability to exactly represent some values in a limited number of bits. Because computer architecture is well beyond this book’s scope, though, we’ll finesse this by saying that your computer’s floating-point hardware is doing the best it can, and neither it nor Python is in error here.

In fact, this is really just a display issue—the interactive prompt’s automatic result echo shows more digits than the print statement here only because it uses a different algorithm. It’s the same number in memory. If you don’t want to see all the digits, use print; as this chapter’s sidebar str and repr Display Formats will explain, you’ll get a user-friendly display. As of 2.7 and 3.1, Python’s floating-point display logic tries to be more intelligent, usually showing fewer decimal digits, but occasionally more.

Note, however, that not all values have so many digits to display:

>>> 1 / 2.0
0.5

and that there are more ways to display the bits of a number inside your computer than using print and automatic echoes (the following are all run in Python 3.3, and may vary slightly in older versions):

>>> num = 1 / 3.0
>>> num                      # Auto-echoes
0.3333333333333333
>>> print(num)               # Print explicitly
0.3333333333333333

>>> '%e' % num               # String formatting expression
'3.333333e-01'
>>> '%4.2f' % num            # Alternative floating-point format
'0.33'
>>> '{0:4.2f}'.format(num)   # String formatting method: Python 2.6, 3.0, and later
'0.33'

The last three of these expressions employ string formatting, a tool that allows for format flexibility, which we will explore in the upcoming chapter on strings (Chapter 7). Its results are strings that are typically printed to displays or reports.

Comparisons: Normal and Chained

So far, we’ve been dealing with standard numeric operations (addition and multiplication), but numbers, like all Python objects, can also be compared. Normal comparisons work for numbers exactly as you’d expect—they compare the relative magnitudes of their operands and return a Boolean result, which we would normally test and take action on in a larger statement and program:

>>> 1 < 2                  # Less than
True
>>> 2.0 >= 1               # Greater than or equal: mixed-type 1 converted to 1.0
True
>>> 2.0 == 2.0             # Equal value
True
>>> 2.0 != 2.0             # Not equal value
False

Notice again how mixed types are allowed in numeric expressions (only); in the second test here, Python compares values in terms of the more complex type, float.

Interestingly, Python also allows us to chain multiple comparisons together to perform range tests. Chained comparisons are a sort of shorthand for larger Boolean expressions. In short, Python lets us string together magnitude comparison tests to code chained comparisons such as range tests. The expression (A < B < C), for instance, tests whether B is between A and C; it is equivalent to the Boolean test (A < B and B < C) but is easier on the eyes (and the keyboard). For example, assume the following assignments:

>>> X = 2
>>> Y = 4
>>> Z = 6

The following two expressions have identical effects, but the first is shorter to type, and it may run slightly faster since Python needs to evaluate Y only once:

>>> X < Y < Z              # Chained comparisons: range tests
True
>>> X < Y and Y < Z
True

The same equivalence holds for false results, and arbitrary chain lengths are allowed:

>>> X < Y > Z
False
>>> X < Y and Y > Z
False

>>> 1 < 2 < 3.0 < 4
True
>>> 1 > 2 > 3.0 > 4
False

You can use other comparisons in chained tests, but the resulting expressions can become nonintuitive unless you evaluate them the way Python does. The following, for instance, is false just because 1 is not equal to 2:

>>> 1 == 2 < 3        # Same as: 1 == 2 and 2 < 3
False                 # Not same as: False < 3 (which means 0 < 3, which is true!)

Python does not compare the 1 == 2 expression’s False result to 3—this would technically mean the same as 0 < 3, which would be True (as we’ll see later in this chapter, True and False are just customized 1 and 0).

One last note here before we move on: chaining aside, numeric comparisons are based on magnitudes, which are generally simple—though floating-point numbers may not always work as you’d expect, and may require conversions or other massaging to be compared meaningfully:

>>> 1.1 + 2.2 == 3.3             # Shouldn't this be True?...
False
>>> 1.1 + 2.2                    # Close to 3.3, but not exactly: limited precision
3.3000000000000003
>>> int(1.1 + 2.2) == int(3.3)   # OK if convert: see also round, floor, trunc ahead
True                             # Decimals and fractions (ahead) may help here too

This stems from the fact that floating-point numbers cannot represent some values exactly due to their limited number of bits—a fundamental issue in numeric programming not unique to Python, which we’ll learn more about later when we meet decimals and fractions, tools that can address such limitations. First, though, let’s continue our tour of Python’s core numeric operations, with a deeper look at division.

Division: Classic, Floor, and True

You’ve seen how division works in the previous sections, so you should know that it behaves slightly differently in Python 3.X and 2.X. In fact, there are actually three flavors of division, and two different division operators, one of which changes in 3.X. This story gets a bit detailed, but it’s another major change in 3.X and can break 2.X code, so let’s get the division operator facts straight:

X / Y

Classic and true division. In Python 2.X, this operator performs classic division, truncating results for integers, and keeping remainders (i.e., fractional parts) for floating-point numbers. In Python 3.X, it performs true division, always keeping remainders in floating-point results, regardless of types.

X // Y

Floor division. Added in Python 2.2 and available in both Python 2.X and 3.X, this operator always truncates fractional remainders down to their floor, regardless of types. Its result type depends on the types of its operands.

True division was added to address the fact that the results of the original classic division model are dependent on operand types, and so can be difficult to anticipate in a dynamically typed language like Python. Classic division was removed in 3.X because of this constraint—the / and // operators implement true and floor division in 3.X. Python 2.X defaults to classic and floor division, but you can enable true division as an option. In sum:

  • In 3.X, the / now always performs true division, returning a float result that includes any remainder, regardless of operand types. The // performs floor division, which truncates the remainder and returns an integer for integer operands or a float if any operand is a float.

  • In 2.X, the / does classic division, performing truncating integer division if both operands are integers and float division (keeping remainders) otherwise. The // does floor division and works as it does in 3.X, performing truncating division for integers and floor division for floats.

Here are the two operators at work in 3.X and 2.X—the first operation in each set is the crucial difference between the lines that may impact code:

C:\code> C:\Python33\python
>>>
>>> 10 / 4            # Differs in 3.X: keeps remainder
2.5
>>> 10 / 4.0          # Same in 3.X: keeps remainder
2.5
>>> 10 // 4           # Same in 3.X: truncates remainder
2
>>> 10 // 4.0         # Same in 3.X: truncates to floor
2.0

C:\code> C:\Python27\python
>>>
>>> 10 / 4            # This might break on porting to 3.X!
2
>>> 10 / 4.0
2.5
>>> 10 // 4           # Use this in 2.X if truncation needed
2
>>> 10 // 4.0
2.0

Notice that the data type of the result for // is still dependent on the operand types in 3.X: if either is a float, the result is a float; otherwise, it is an integer. Although this may seem similar to the type-dependent behavior of / in 2.X that motivated its change in 3.X, the type of the return value is much less critical than differences in the return value itself.

Moreover, because // was provided in part as a compatibility tool for programs that rely on truncating integer division (and this is more common than you might expect), it must return integers for integers. Using // instead of / in 2.X when integer truncation is required helps make code 3.X-compatible.

Supporting either Python

Although / behavior differs in 2.X and 3.X, you can still support both versions in your code. If your programs depend on truncating integer division, use // in both 2.X and 3.X as just mentioned. If your programs require floating-point results with remainders for integers, use float to guarantee that one operand is a float around a / when run in 2.X:

X = Y // Z        # Always truncates, always an int result for ints in 2.X and 3.X

X = Y / float(Z)  # Guarantees float division with remainder in either 2.X or 3.X

Alternatively, you can enable 3.X / division in 2.X with a __future__ import, rather than forcing it with float conversions:

C:\code> C:\Python27\python
>>> from __future__ import division         # Enable 3.X "/" behavior
>>> 10 / 4
2.5
>>> 10 // 4                                 # Integer // is the same in both
2

This special from statement applies to the rest of your session when typed interactively like this, and must appear as the first executable line when used in a script file (and alas, we can import from the future in Python, but not the past; insert something about talking to “the Doc” here...).

Floor versus truncation

One subtlety: the // operator is informally called truncating division, but it’s more accurate to refer to it as floor division—it truncates the result down to its floor, which means the closest whole number below the true result. The net effect is to round down, not strictly truncate, and this matters for negatives. You can see the difference for yourself with the Python math module (modules must be imported before you can use their contents; more on this later):

>>> import math
>>> math.floor(2.5)           # Closest number below value
2
>>> math.floor(-2.5)
-3
>>> math.trunc(2.5)           # Truncate fractional part (toward zero)
2
>>> math.trunc(-2.5)
-2

When running division operators, you only really truncate for positive results, since truncation is the same as floor; for negatives, it’s a floor result (really, they are both floor, but floor is the same as truncation for positives). Here’s the case for 3.X:

C:\code> c:\python33\python
>>> 5 / 2, 5 / −2
(2.5, −2.5)

>>> 5 // 2, 5 // −2           # Truncates to floor: rounds to first lower integer
(2, −3)                       # 2.5 becomes 2, −2.5 becomes −3

>>> 5 / 2.0, 5 / −2.0
(2.5, −2.5)

>>> 5 // 2.0, 5 // −2.0       # Ditto for floats, though result is float too
(2.0, −3.0)

The 2.X case is similar, but / results differ again:

C:code> c:\python27\python
>>> 5 / 2, 5 / −2             # Differs in 3.X
(2, −3)

>>> 5 // 2, 5 // −2           # This and the rest are the same in 2.X and 3.X
(2, −3)

>>> 5 / 2.0, 5 / −2.0
(2.5, −2.5)

>>> 5 // 2.0, 5 // −2.0
(2.0, −3.0)

If you really want truncation toward zero regardless of sign, you can always run a float division result through math.trunc, regardless of Python version (also see the round built-in for related functionality, and the int built-in, which has the same effect here but requires no import):

C:\code> c:\python33\python
>>> import math
>>> 5 / −2                      # Keep remainder
−2.5
>>> 5 // −2                     # Floor below result
-3
>>> math.trunc(5 / −2)          # Truncate instead of floor (same as int())
−2

C:\code> c:\python27\python
>>> import math
>>> 5 / float(−2)               # Remainder in 2.X
−2.5
>>> 5 / −2, 5 // −2             # Floor in 2.X
(−3, −3)
>>> math.trunc(5 / float(−2))   # Truncate in 2.X
−2

Why does truncation matter?

As a wrap-up, if you are using 3.X, here is the short story on division operators for reference:

>>> (5 / 2), (5 / 2.0), (5 / −2.0), (5 / −2)        # 3.X true division
(2.5, 2.5, −2.5, −2.5)

>>> (5 // 2), (5 // 2.0), (5 // −2.0), (5 // −2)    # 3.X floor division
(2, 2.0, −3.0, −3)

>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0)        # Both
(3.0, 3.0, 3, 3.0)

For 2.X readers, division works as follows (the three bold outputs of integer division differ from 3.X):

>>> (5 / 2), (5 / 2.0), (5 / −2.0), (5 / −2)        # 2.X classic division (differs)
(2, 2.5, −2.5, −3)

>>> (5 // 2), (5 // 2.0), (5 // −2.0), (5 // −2)    # 2.X floor division (same)
(2, 2.0, −3.0, −3)

>>> (9 / 3), (9.0 / 3), (9 // 3), (9 // 3.0)        # Both
(3, 3.0, 3, 3.0)

It’s possible that the nontruncating behavior of / in 3.X may break a significant number of 2.X programs. Perhaps because of a C language legacy, many programmers rely on division truncation for integers and will have to learn to use // in such contexts instead. You should do so in all new 2.X and 3.X code you write today—in the former for 3.X compatibility, and in the latter because / does not truncate in 3.X. Watch for a simple prime number while loop example in Chapter 13, and a corresponding exercise at the end of Part IV that illustrates the sort of code that may be impacted by this / change. Also stay tuned for more on the special from command used in this section; it’s discussed further in Chapter 25.

Integer Precision

Division may differ slightly across Python releases, but it’s still fairly standard. Here’s something a bit more exotic. As mentioned earlier, Python 3.X integers support unlimited size:

>>> 999999999999999999999999999999 + 1         # 3.X
1000000000000000000000000000000

Python 2.X has a separate type for long integers, but it automatically converts any number too large to store in a normal integer to this type. Hence, you don’t need to code any special syntax to use longs, and the only way you can tell that you’re using 2.X longs is that they print with a trailing “L”:

>>> 999999999999999999999999999999 + 1         # 2.X
1000000000000000000000000000000L

Unlimited-precision integers are a convenient built-in tool. For instance, you can use them to count the U.S. national debt in pennies in Python directly (if you are so inclined, and have enough memory on your computer for this year’s budget). They are also why we were able to raise 2 to such large powers in the examples in Chapter 3. Here are the 3.X and 2.X cases:

>>> 2 ** 200
1606938044258990275541962092341162602522202993782792835301376

>>> 2 ** 200
1606938044258990275541962092341162602522202993782792835301376L

Because Python must do extra work to support their extended precision, integer math is usually substantially slower than normal when numbers grow large. However, if you need the precision, the fact that it’s built in for you to use will likely outweigh its performance penalty.

Complex Numbers

Although less commonly used than the types we’ve been exploring thus far, complex numbers are a distinct core object type in Python. They are typically used in engineering and science applications. If you know what they are, you know why they are useful; if not, consider this section optional reading.

Complex numbers are represented as two floating-point numbers—the real and imaginary parts—and you code them by adding a j or J suffix to the imaginary part. We can also write complex numbers with a nonzero real part by adding the two parts with a +. For example, the complex number with a real part of 2 and an imaginary part of −3 is written 2 + −3j. Here are some examples of complex math at work:

>>> 1j * 1J
(-1+0j)
>>> 2 + 1j * 3
(2+3j)
>>> (2 + 1j) * 3
(6+3j)

Complex numbers also allow us to extract their parts as attributes, support all the usual mathematical expressions, and may be processed with tools in the standard cmath module (the complex version of the standard math module). Because complex numbers are rare in most programming domains, though, we’ll skip the rest of this story here. Check Python’s language reference manual for additional details.

Hex, Octal, Binary: Literals and Conversions

Python integers can be coded in hexadecimal, octal, and binary notation, in addition to the normal base-10 decimal coding we’ve been using so far. The first three of these may at first seem foreign to 10-fingered beings, but some programmers find them convenient alternatives for specifying values, especially when their mapping to bytes and bits is important. The coding rules were introduced briefly at the start of this chapter; let’s look at some live examples here.

Keep in mind that these literals are simply an alternative syntax for specifying the value of an integer object. For example, the following literals coded in Python 3.X or 2.X produce normal integers with the specified values in all three bases. In memory, an integer’s value is the same, regardless of the base we use to specify it:

>>> 0o1, 0o20, 0o377           # Octal literals: base 8, digits 0-7 (3.X, 2.6+)
(1, 16, 255)
>>> 0x01, 0x10, 0xFF           # Hex literals: base 16, digits 0-9/A-F (3.X, 2.X)
(1, 16, 255)
>>> 0b1, 0b10000, 0b11111111   # Binary literals: base 2, digits 0-1 (3.X, 2.6+)
(1, 16, 255)

Here, the octal value 0o377, the hex value 0xFF, and the binary value 0b11111111 are all decimal 255. The F digits in the hex value, for example, each mean 15 in decimal and a 4-bit 1111 in binary, and reflect powers of 16. Thus, the hex value 0xFF and others convert to decimal values as follows:

>>> 0xFF, (15 * (16 ** 1)) + (15 * (16 ** 0))     # How hex/binary map to decimal
(255, 255)
>>> 0x2F, (2  * (16 ** 1)) + (15 * (16 ** 0))
(47, 47)
>>> 0xF, 0b1111, (1*(2**3) + 1*(2**2) + 1*(2**1) + 1*(2**0))
(15, 15, 15)

Python prints integer values in decimal (base 10) by default but provides built-in functions that allow you to convert integers to other bases’ digit strings, in Python-literal form—useful when programs or users expect to see values in a given base:

>>> oct(64), hex(64), bin(64)               # Numbers=>digit strings
('0o100', '0x40', '0b1000000')

The oct function converts decimal to octal, hex to hexadecimal, and bin to binary. To go the other way, the built-in int function converts a string of digits to an integer, and an optional second argument lets you specify the numeric base—useful for numbers read from files as strings instead of coded in scripts:

>>> 64, 0o100, 0x40, 0b1000000              # Digits=>numbers in scripts and strings
(64, 64, 64, 64)

>>> int('64'), int('100', 8), int('40', 16), int('1000000', 2)
(64, 64, 64, 64)

>>> int('0x40', 16), int('0b1000000', 2)    # Literal forms supported too
(64, 64)

The eval function, which you’ll meet later in this book, treats strings as though they were Python code. Therefore, it has a similar effect, but usually runs more slowly—it actually compiles and runs the string as a piece of a program, and it assumes the string being run comes from a trusted source—a clever user might be able to submit a string that deletes files on your machine, so be careful with this call:

>>> eval('64'), eval('0o100'), eval('0x40'), eval('0b1000000')
(64, 64, 64, 64)

Finally, you can also convert integers to base-specific strings with string formatting method calls and expressions, which return just digits, not Python literal strings:

>>> '{0:o}, {1:x}, {2:b}'.format(64, 64, 64)     # Numbers=>digits, 2.6+
'100, 40, 1000000'

>>> '%o, %x, %x, %X' % (64, 64, 255, 255)        # Similar, in all Pythons
'100, 40, ff, FF'

String formatting is covered in more detail in Chapter 7.

Two notes before moving on. First, per the start of this chapter, Python 2.X users should remember that you can code octals with simply a leading zero, the original octal format in Python:

>>> 0o1, 0o20, 0o377     # New octal format in 2.6+ (same as 3.X)
(1, 16, 255)
>>> 01, 020, 0377        # Old octal literals in all 2.X (error in 3.X)
(1, 16, 255)

In 3.X, the syntax in the second of these examples generates an error. Even though it’s not an error in 2.X, be careful not to begin a string of digits with a leading zero unless you really mean to code an octal value. Python 2.X will treat it as base 8, which may not work as you’d expect—010 is always decimal 8 in 2.X, not decimal 10 (despite what you may or may not think!). This, along with symmetry with the hex and binary forms, is why the octal format was changed in 3.X—you must use 0o010 in 3.X, and probably should in 2.6 and 2.7 both for clarity and forward-compatibility with 3.X.

Secondly, note that these literals can produce arbitrarily long integers. The following, for instance, creates an integer with hex notation and then displays it first in decimal and then in octal and binary with converters (run in 3.X here: in 2.X the decimal and octal displays have a trailing L to denote its separate long type, and octals display without the letter o):

>>> X = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF
>>> X
5192296858534827628530496329220095
>>> oct(X)
'0o17777777777777777777777777777777777777'
>>> bin(X)
'0b111111111111111111111111111111111111111111111111111111111 ...and so on... 11111'

Speaking of binary digits, the next section shows tools for processing individual bits.

Bitwise Operations

Besides the normal numeric operations (addition, subtraction, and so on), Python supports most of the numeric expressions available in the C language. This includes operators that treat integers as strings of binary bits, and can come in handy if your Python code must deal with things like network packets, serial ports, or packed binary data produced by a C program.

We can’t dwell on the fundamentals of Boolean math here—again, those who must use it probably already know how it works, and others can often postpone the topic altogether—but the basics are straightforward. For instance, here are some of Python’s bitwise expression operators at work performing bitwise shift and Boolean operations on integers:

>>> x = 1               # 1 decimal is 0001 in bits
>>> x << 2              # Shift left 2 bits: 0100
4
>>> x | 2               # Bitwise OR (either bit=1): 0011
3
>>> x & 1               # Bitwise AND (both bits=1): 0001
1

In the first expression, a binary 1 (in base 2, 0001) is shifted left two slots to create a binary 4 (0100). The last two operations perform a binary OR to combine bits (0001|0010 = 0011) and a binary AND to select common bits (0001&0001 = 0001). Such bit-masking operations allow us to encode and extract multiple flags and other values within a single integer.

This is one area where the binary and hexadecimal number support in Python as of 3.0 and 2.6 become especially useful—they allow us to code and inspect numbers by bit-strings:

>>> X = 0b0001          # Binary literals
>>> X << 2              # Shift left
4
>>> bin(X << 2)         # Binary digits string
'0b100'

>>> bin(X | 0b010)      # Bitwise OR: either
'0b11'
>>> bin(X & 0b1)        # Bitwise AND: both
'0b1'

This is also true for values that begin life as hex literals, or undergo base conversions:

>>> X = 0xFF            # Hex literals
>>> bin(X)
'0b11111111'
>>> X ^ 0b10101010      # Bitwise XOR: either but not both
85
>>> bin(X ^ 0b10101010)
'0b1010101'

>>> int('01010101', 2)  # Digits=>number: string to int per base
85
>>> hex(85)             # Number=>digits: Hex digit string
'0x55'

Also in this department, Python 3.1 and 2.7 introduced a new integer bit_length method, which allows you to query the number of bits required to represent a number’s value in binary. You can often achieve the same effect by subtracting 2 from the length of the bin string using the len built-in function we met in Chapter 4 (to account for the leading “0b”), though it may be less efficient:

>>> X = 99
>>> bin(X), X.bit_length(), len(bin(X)) - 2
('0b1100011', 7, 7)
>>> bin(256), (256).bit_length(), len(bin(256)) - 2
('0b100000000', 9, 9)

We won’t go into much more detail on such “bit twiddling” here. It’s supported if you need it, but bitwise operations are often not as important in a high-level language such as Python as they are in a low-level language such as C. As a rule of thumb, if you find yourself wanting to flip bits in Python, you should think about which language you’re really coding. As we’ll see in upcoming chapters, Python’s lists, dictionaries, and the like provide richer—and usually better—ways to encode information than bit strings, especially when your data’s audience includes readers of the human variety.

Other Built-in Numeric Tools

In addition to its core object types, Python also provides both built-in functions and standard library modules for numeric processing. The pow and abs built-in functions, for instance, compute powers and absolute values, respectively. Here are some examples of the built-in math module (which contains most of the tools in the C language’s math library) and a few built-in functions at work in 3.3; as described earlier, some floating-point displays may show more or fewer digits in Pythons before 2.7 and 3.1:

>>> import math
>>> math.pi, math.e                               # Common constants
(3.141592653589793, 2.718281828459045)

>>> math.sin(2 * math.pi / 180)                   # Sine, tangent, cosine
0.03489949670250097

>>> math.sqrt(144), math.sqrt(2)                  # Square root
(12.0, 1.4142135623730951)

>>> pow(2, 4), 2 ** 4, 2.0 ** 4.0                 # Exponentiation (power)
(16, 16, 16.0)

>>> abs(-42.0), sum((1, 2, 3, 4))                 # Absolute value, summation
(42.0, 10)

>>> min(3, 1, 2, 4), max(3, 1, 2, 4)              # Minimum, maximum
(1, 4)

The sum function shown here works on a sequence of numbers, and min and max accept either a sequence or individual arguments. There are a variety of ways to drop the decimal digits of floating-point numbers. We met truncation and floor earlier; we can also round, both numerically and for display purposes:

>>> math.floor(2.567), math.floor(-2.567)         # Floor (next-lower integer)
(2, −3)

>>> math.trunc(2.567), math.trunc(−2.567)         # Truncate (drop decimal digits)
(2, −2)

>>> int(2.567), int(−2.567)                       # Truncate (integer conversion)
(2, −2)

>>> round(2.567), round(2.467), round(2.567, 2)   # Round (Python 3.X version)
(3, 2, 2.57)

>>> '%.1f' % 2.567, '{0:.2f}'.format(2.567)       # Round for display (Chapter 7)
('2.6', '2.57')

As we saw earlier, the last of these produces strings that we would usually print and supports a variety of formatting options. As also described earlier, the second-to-last test here will also output (3, 2, 2.57) prior to 2.7 and 3.1 if we wrap it in a print call to request a more user-friendly display. String formatting is still subtly different, though, even in 3.X; round rounds and drops decimal digits but still produces a floating-point number in memory, whereas string formatting produces a string, not a number:

>>> (1 / 3.0), round(1 / 3.0, 2), ('%.2f' % (1 / 3.0))
(0.3333333333333333, 0.33, '0.33')

Interestingly, there are three ways to compute square roots in Python: using a module function, an expression, or a built-in function (if you’re interested in performance, we will revisit these in an exercise and its solution at the end of Part IV, to see which runs quicker):

>>> import math
>>> math.sqrt(144)              # Module
12.0
>>> 144 ** .5                   # Expression
12.0
>>> pow(144, .5)                # Built-in
12.0

>>> math.sqrt(1234567890)       # Larger numbers
35136.41828644462
>>> 1234567890 ** .5
35136.41828644462
>>> pow(1234567890, .5)
35136.41828644462

Notice that standard library modules such as math must be imported, but built-in functions such as abs and round are always available without imports. In other words, modules are external components, but built-in functions live in an implied namespace that Python automatically searches to find names used in your program. This namespace simply corresponds to the standard library module called builtins in Python 3.X (and __builtin__ in 2.X). There is much more about name resolution in the function and module parts of this book; for now, when you hear “module,” think “import.”

The standard library random module must be imported as well. This module provides an array of tools, for tasks such as picking a random floating-point number between 0 and 1, and selecting a random integer between two numbers:

>>> import random
>>> random.random()
0.5566014960423105
>>> random.random()              # Random floats, integers, choices, shuffles
0.051308506597373515

>>> random.randint(1, 10)
5
>>> random.randint(1, 10)
9

This module can also choose an item at random from a sequence, and shuffle a list of items randomly:

>>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
'Holy Grail'
>>> random.choice(['Life of Brian', 'Holy Grail', 'Meaning of Life'])
'Life of Brian'

>>> suits = ['hearts', 'clubs', 'diamonds', 'spades']
>>> random.shuffle(suits)
>>> suits
['spades', 'hearts', 'diamonds', 'clubs']
>>> random.shuffle(suits)
>>> suits
['clubs', 'diamonds', 'hearts', 'spades']

Though we’d need additional code to make this more tangible here, the random module can be useful for shuffling cards in games, picking images at random in a slideshow GUI, performing statistical simulations, and much more. We’ll deploy it again later in this book (e.g., in Chapter 20’s permutations case study), but for more details, see Python’s library manual.