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.
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 |
---|---|
|
Normal integers (C longs) |
|
Long integers (unlimited size) |
|
Floating-point (C doubles) |
|
Octal and hex constants |
|
Complex number constants |
By and large, Python’s numeric types are straightforward, but a few are worth highlighting here:
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.
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.
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!
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.
Besides the built-in number types shown in Table 2.2, Python provides a set of tools for processing number objects:
+
, *
,
>>
, **
, etc.
pow
, abs
, etc.
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.
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 |
---|---|
Logical | |
|
Logical |
|
Logical negation |
sequence membership | |
Bitwise | |
|
Bitwise |
|
Bitwise |
Shift | |
Addition/concatenation, subtraction | |
Multiplication/repetition, division, remainder/format | |
Unary negation, identity, bitwise complement | |
|
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.
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 +
.
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.
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.
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.[9]
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.
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.
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.[10]
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.
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.[11] 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:
>>>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.
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.”
[9] 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.
[10] 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.
[11] 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.