I l@ve RuBoard Previous Section Next Section

2.3 Numbers

On to the nitty-gritty. The first object type on our tour is Python numbers. In general, Python's number types are fairly typical and will seem familiar if you've used just about any other programming language in the past. Python supports the usual numeric types (integer and floating point), constants, and expressions. In addition, Python provides more advanced numeric programming support, including a complex number type, an unlimited precision integer, and a variety of numeric tool libraries. The next few sections give an overview of the numeric support in Python.

2.3.1 Standard Numeric Types

Among its basic types, Python supports the usual suspects: both integer and floating-point numbers, and all their associated syntax and operations. Like C, Python also allows you to write integers using hexadecimal and octal constants. Unlike C, Python also has a complex number type (introduced in Python 1.4), as well as a long integer type with unlimited precision (it can grow to have as many digits as your memory space allows). Table 2.2 shows what Python's numeric types look like when written out in a program (i.e., as constants).

Table 2.2. Numeric Constants

Constant

Interpretation

1234, -24, 0

Normal integers (C longs)

999999999999L

Long integers (unlimited size)

1.23, 3.14e-10, 4E210, 4.0e+210

Floating-point (C doubles)

0177, 0x9ff

Octal and hex constants

3+4j, 3.0+4.0j, 3J

Complex number constants

By and large, Python's numeric types are straightforward, but a few are worth highlighting here:

Integer and floating-point constants

Integers are written as a string of decimal digits. Floating-point numbers have an embedded decimal point, and/or an optional signed exponent introduced by an e or E. If you write a number with a decimal point or exponent, Python makes it a floating-point object and uses floating-point (not integer) math when it's used in an expression. The rules for writing floating-point numbers are the same as with C.

Numeric precision

Plain Python integers (row 1) are implemented as C longs internally (i.e., at least 32 bits), and Python floating-point numbers are implemented as C doubles; Python numbers get as much precision as the C compiler used to build the Python interpreter gives to longs and doubles. On the other hand, if an integer constant ends with an l or L, it becomes a Python long integer (not to be confused with a C long) and can grow as large as needed.

H exadecimal and octal constants

The rules for writing hexadecimal (base 16) and octal (base 8) integers are the same as in C: octal constants start with a leading zero (0), and hexadecimals start with a leading 0x or 0X. Notice that this means you can't write normal base-ten integers with a leading zero (e.g., 01); Python interprets them as octal constants, which usually don't work as you'd expect!

Complex numbers

Python complex constants are written as real-part + imaginary-part, and terminated with a j or J. Internally, they are implemented as a pair of floating-point numbers, but all numeric operations perform complex math when applied to complex numbers.

2.3.2 Built-in Tools and Extensions

Besides the built-in number types shown in Table 2.2, Python provides a set of tools for processing number objects:

Expression operators

+, *, >>, **, etc.

Built-in mathematical functions

pow, abs, etc.

Utility modules

rand, math, etc.

We'll meet all of these as we go along. Finally, if you need to do serious number-crunching, an optional extension for Python called Numeric Python provides advanced numeric programming tools, such as a matrix data type and sophisticated computation libraries. Because it's so advanced, we won't say more about Numeric Python in this chapter; see the examples later in the book and Appendix A. Also note that, as of this writing, Numeric Python is an optional extension; it doesn't come with Python and must be installed separately.

2.3.3 Python Expression Operators

Perhaps the most fundamental tool that processes numbers is the expression : a combination of numbers (or other objects) and operators that computes a value when executed by Python. In Python, expressions are written using the usual mathematical notation and operator symbols. For instance, to add two numbers X and Y, we say X + Y, which tells Python to apply the + operator to the values named by X and Y. The result of the expression is the sum of X and Y, another number object.

Table 2.3 lists all the operator expressions available in Python. Many are self-explanatory; for instance, the usual mathematical operators are supported: +, -, *, /, and so on. A few will be familiar if you've used C in the past: % computes a division remainder, << performs a bitwise left-shift, & computes a bitwise and result, etc. Others are more Python-specific, and not all are numeric in nature: the is operator tests object identity (i.e., address) equality, lambda creates unnamed functions, and so on.

Table 2.3. Python Expression Operators and Precedence

Operators

Description

x or y,

lambda args: expression

Logical or ( y is evaluated only if x is false), anonymous function

x and y

Logical and (y is evaluated only if x is true)

not x

Logical negation

in, not in

sequence membership

x | y

Bitwise or

x ^ y

Bitwise exclusive or

x & y

Bitwise and

x << y, x >> y

Shift x left or right by y bits

x + y, x - y

Addition/concatenation, subtraction

x * y, x / y, x % y

Multiplication/repetition, division, remainder/format

-x, +x, ~x

Unary negation, identity, bitwise complement

x[i], x[i:j], x.y, x(...)

Indexing, slicing, qualification, function calls

(...), [...], {...}, `...`

Tuple, list, dictionary, conversion to string

Table 2.3 is mostly included for reference; since we'll see its operators in action later, we won't describe every entry here. But there are a few basic points we'd like to make about expressions before moving on.

2.3.3.1 Mixed operators: Operators bind tighter lower in the table

As in most languages, more complex expressions are coded by stringing together operator expressions in the table. For instance, the sum of two multiplications might be written as: A * B + C * D. So how does Python know which operator to perform first? When you write an expression with more than one operator, Python groups its parts according to what are called precedence rules, and this grouping determines the order in which expression parts are computed. In the table, operators lower in the table have higher precedence and so bind more tightly in mixed expressions. For example, if you write X + Y * Z, Python evaluates the multiplication first (Y * Z), then adds that result to X, because * has higher precedence (is lower in the table) than +.

2.3.3.2 Parentheses group subexpressions

If the prior paragraph sounded confusing, relax: you can forget about precedence completely if you're careful to group parts of expressions with parentheses. When you parenthesize subexpressions, you override Python precedence rules; Python always evaluates parenthesized expressions first, before using their results in enclosing expressions. For instance, instead of X + Y * Z, write (X + Y) * Z, or for that matter X + (Y * Z) to force Python to evaluate the expression in the desired order. In the former case, + is applied to X and Y first; in the latter, the * is performed first (as if there were no parentheses at all). Generally speaking, adding parentheses in big expressions is a great idea; it not only forces the evaluation order you want, but it also aids readability.

2.3.3.3 Mixed types: Converted up just as in C

Besides mixing operators in expressions, you can also mix numeric types. For instance, you can add an integer to a floating-point number, but this leads to another dilemma: what type is the result—integer or floating-point? The answer is simple, especially if you've used almost any other language before: in mixed type expressions, Python first converts operands up to the type of the most complex operand, and then performs the math on same-type operands. Python ranks the complexity of numeric types like so: integers are simpler than long integers, which are simpler than floating-point numbers, which are simpler than complex numbers. So, when an integer is mixed with a floating-point, the integer is converted up to a floating-point value first, and then floating-point math yields the floating-point result. Similarly, any mixed-type expression where one operand is a complex number results in the other operand being converted up to a complex, and yields a complex result.

2.3.3.4 Preview: operator overloading

Although we're focusing on built-in numbers right now, keep in mind that all Python operators may be overloaded by Python classes and C extension types, to work on objects you implement. For instance, you'll see later that objects coded with classes may be added with + expressions, indexed with [i] expressions, and so on. Furthermore, some operators are already overloaded by Python itself: they perform different actions depending on the type of built-in objects being processed. For example, the + operator performs addition when applied to numbers, but (as we'll see in a moment) performs concatenation when applied to sequence objects such as strings and lists.[2]

[2] This is usually called polymorphism—the meaning of an operation depends on the type of objects being operated on. But we're not quite ready for object-oriented ideas like this yet, so hold that thought for now.

2.3.4 Numbers in Action

Perhaps the best way to understand numeric objects and expressions is to see them in action. Let's fire up the interactive command line and type some basic, but illustrative operations.

2.3.4.1 Basic operations

First of all, let's exercise some basic math: addition and division. In the following interaction, we first assign two variables (a and b) to integers, so we can use them later in a larger expression. We'll say more about this later, but in Python, variables are created when first assigned; there is no need to predeclare the names a and b before using them. In other words, the assignments cause these variables to spring into existence automatically.

% python
>>> a = 3           # name created
>>> b = 4

We've also used a comment here. These were introduced in Chapter 1, but as a refresher: 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 (it's a place for you to write human-readable documentation for your code; since code you type interactively is temporary, you won't normally write comments there, but we've added them to our examples to help explain the code). Now, let's use our integer objects in expressions; as usual, expression results are echoed back to us at the interactive prompt:

>>> b / 2 + a       # same as ((4 / 2) + 3)
5
>>> b / (2.0 + a)   # same as (4 / (2.0 + 3))
0.8

In the first expression, there are no parentheses, so Python automatically groups the components according to its precedence rules; since / is lower in Table 2.3 than +, it binds more tightly, and so is evaluated first. The result is as if we had parenthesized the expression 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 performs integer division and addition.

In the second expression, we add parentheses 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 up to a floating-point value (3.0) before performing the +. It also converts b up to a floating-point value (4.0) and performs a floating-point division: (4.0 / 5.0) yields a floating-point result of 0.8. If this were integer division instead, the result would be a truncated integer zero.

2.3.4.2 B itwise operations

Besides the normal numeric operations (addition, subtraction, and so on), Python supports most of the numeric expressions available in the C language. For instance, here it's at work performing bitwise shift and Boolean operations:

>>> x = 1        # 0001
>>> x << 2       # shift left 2 bits: 0100
4
>>> x | 2        # bitwise OR: 0011
3
>>> x & 1        # bitwise AND: 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 (0001 | 0010 = 0011), and a binary and (0001 & 0001 = 0001). We won't go into much more detail on bit-twiddling here. It's supported if you need it, but be aware that it's often not as important in a high-level language such as Python as it is 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 long and hard about which language you're really using. In general, there are often better ways to encode information in Python than bit strings.[3]

[3] Usually. As for every rule there are exceptions. For instance, if you interface with C libraries that expect bit strings to be passed in, our preaching doesn't apply.

2.3.4.3 L ong integers

Now for something more exotic: here's a look at long integers in action. When an integer constant ends with an L (or lowercase l), Python creates a long integer, which can be arbitrarily big:

>>> 9999999999999999999999999999 + 1
OverflowError: integer literal too large
>>> 9999999999999999999999999999L + 1
10000000000000000000000000000L

Here, the first expression fails and raises an error, because normal integers can't accommodate such a large number. On the other hand, the second works fine, because we tell Python to generate a long integer object instead.

Long integers are a convenient tool. In fact, you can use them to count the national debt in pennies, if you are so inclined. But because Python must do extra work to support their extended precision, long integer math is usually much slower than normal integer math. If you need the precision, it's built in for you to use. But as usual, there's no such thing as a free lunch.


2.3.4.4 Complex numbers

C omplex numbers are a recent addition to Python. If you know what they are, you know why they are useful; if not, consider this section optional reading.[4] Complex numbers are represented as two floating-point numbers—the real and imaginary parts—and are coded 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. Some examples of complex math at work:

[4] One of your authors is quick to point out that he has never had a need for complex numbers in some 15 years of development work. The other author isn't so lucky.

>>> 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, but since complex math is an advanced tool, check Python's language reference manual for additional details.

2.3.4.5 Other numeric tools

As mentioned above, Python also provides both built-in functions and built-in modules for numeric processing. Here are the built-in math module and a few built-in functions at work; we'll meet more built-ins in Chapter 8.

>>> import math
>>> math.pi
3.14159265359
>>>
>>> abs(-42), 2**4, pow(2, 4)
(42, 16, 16)

Notice that built-in modules such as math must be imported and qualified, but built-in functions such as abs are always available without imports. Really, modules are external components, but built-in functions live in an implied namespace, which Python searches to find names used in your program. This namespace corresponds to the module called _ _builtin__. We talk about name resolution in Chapter 4; for now, when we say "module", think "import."

I l@ve RuBoard Previous Section Next Section