Now that we’ve seen Python’s core built-in object types, this chapter explores its fundamental statement forms. In simple terms, statements are the things you write to tell Python what your programs should do. If programs do things with stuff, statements are the way you specify what sort of things a program does. Python is a procedural, statement-based language; by combining statements, you specify a procedure that Python performs to satisfy a program’s goals.
Another way to understand the role of statements is to revisit the concept hierarchy introduced in Chapter 4, which talked about built-in objects and the expressions used to manipulate them. This chapter climbs the hierarchy to the next level:
Programs are composed of modules.
Modules contain statements.
Statements contain expressions.
Expressions create and process objects.
At its core, Python syntax is composed of statements and expressions. Expressions process objects, and are embedded in statements. Statements code the larger logic of a program’s operation—they use and direct expressions to process the objects we’ve already seen. Moreover, statements are where objects spring into existence (e.g., in expressions within assignment statements), and some statements create entirely new kinds of objects (functions, classes, and so on). Statements always exist in modules, which themselves are managed with statements.
Table 8-1 summarizes Python’s
statement set. Part III deals with entries in
the table through break
and
continue
. You’ve informally been
introduced to a few of the statements in Table 8-1. Part III will fill in
details that were skipped earlier, introduce the rest of
Python’s procedural statement set, and cover the
overall syntax model.
Statements that have to do with larger program units—functions,
classes, modules, and exceptions—lead to larger programming
ideas, so they will each have a section of their own. More exotic
statements like exec
(which compiles and executes
code constructed as strings) are covered later in the book, or in
Python standard documentation.
We’ve been using the Python assignment statement already, to assign objects to names. In its basic form, you write a target of an assignment on the left of an equals sign and an object to be assigned on the right. The target on the left may be a name or object component, and the object on the right can be an arbitrary expression that computes an object. For the most part, assignment is straightforward to use, but here are a few properties to keep in mind:
Python assignment stores references to objects in names or data structure slots. It always creates references to objects, instead of copying objects. Because of that, Python variables are much more like pointers than data storage areas.
Names are created when first assigned. Python creates variable names the first time you assign them a value (an object reference). There’s no need to predeclare names ahead of time. Some (but not all) data structure slots are created when assigned too (e.g., dictionary entries, some object attributes). Once assigned, a name is replaced by the value it references whenever it appears in an expression.
Names must be assigned before being referenced. Conversely, it’s an error to use a name you haven’t assigned a value to yet. Python raises an exception if you try, rather than returning some sort of ambiguous (and hard to notice) default value.
Implicit assignments:
import
, from
,
def
, class
,
for
, function arguments. In this section, we’re concerned with the
=
statement, but assignment occurs in many
contexts in Python. For instance, we’ll see later
that module imports, function and class definitions,
for
loop variables, and function arguments, are
all implicit assignments. Since assignment works the same everywhere
it pops up, all these contexts simply bind names to object references
at runtime.
Table 8-2 illustrates the different assignment statements in Python. In addition to this table, Python includes a set of assignment statement forms known as augmented assignment.
Operation |
Interpretation |
|
Basic form |
|
Tuple assignment (positional) |
|
List assignment (positional) |
|
Multiple-target |
The first line in Table 8-2 is by far the most common: binding a single object to a name (or data-structure slot). The other table entries represent special forms:
The second and third lines are related. When you code
tuples
or lists on the left side of the =
, Python pairs
objects on the right side with targets on the left and assigns them
from left to right. For example, in the second line of the table,
name spam
is assigned the string
'yum
', and name ham
is bound to
string 'YUM
‘. Internally, Python makes a tuple of
the items on the right first, so this is often called tuple (and
list) unpacking assignment.
The last line in Table 8-2 shows the
multiple-target form of assignment. In this form, Python assigns a
reference to the same object (the object farthest to the right) to
all the targets on the left. In the table, names
spam
and ham
would both be
assigned a reference to the same string object
'lunch
', and so share the same reference to the
object. The effect is the same as if you had coded
ham='lunch
', followed by
spam=ham
, since ham
evaluates
to the original string object.
We’ve already used basic assignment. Here are a few simple examples of unpacking assignment in action:
%python
>>>nudge = 1
>>>wink = 2
>>>A, B = nudge, wink # Tuple assignment
>>>A, B # Like A = nudge; B = wink
(1, 2) >>>[C, D] = [nudge, wink] # List assignment
>>>C, D
(1, 2)
Tuple assignment leads to a common coding trick in Python that was introduced in a solution to the exercises from Part II. Since Python creates a temporary tuple that saves the values on the right, unpacking assignments are also a way to swap two variables’ values without creating a temporary of your own:
>>>nudge = 1
>>>wink = 2
>>>nudge, wink = wink, nudge # Tuples: swaps values
>>>nudge, wink # Like T = nudge; nudge = wink; wink = T
(2, 1)
The tuple and list assignment forms are generalized to accept any type of sequence on the right, as long as it is of the same length. You can assign a tuple of values to a list of variables, a string of characters to a tuple of variables, and so on. In all cases, Python assigns items in the sequence on the right to variables in the sequence on the left by position, from left to right:
>>>[a, b, c] = (1, 2, 3)
>>>a, c
(1, 3) >>>(a, b, c) = "ABC"
>>>a, c
('A', 'C')
Unpacking assignment also gives rise to another common coding idiom in Python: assigning an integer series to a set of variables:
>>>red, green, blue = range(3)
>>>red, blue
(0, 2)
This initializes the three names to integer codes 0, 1, and 2,
respectively (it’s Python’s
equivalent of enumerated data types you may have
seen in other languages). To make sense of this, you also need to
know that the range
built-in function generates a
list of successive integers:
>>> range(3)
[0, 1, 2]
Since range
is commonly used in
for
loops, we’ll say more about
it in Chapter 10.
Now that we’ve seen assignment statements, it is also time to get more formal in the use of variable names. In Python, names come into existence when you assign values to them, but there are a few rules to follow when picking names for things in our program:
Variable names must start with an underscore or letter, and be
followed by any number of letters, digits, or underscores.
_spam
, spam
, and
Spam_1
are legal names, but
1_Spam
, spam$
, and
@#!
are not.
Python always pays attention to case in programs, both in names you
create and in reserved words. For instance, names
X
and x
refer to two different
variables.
Names we define cannot be the same as words that mean special things
in the Python language. For instance, if we try to use a variable
name like class
, Python will raise a syntax error,
but klass
and Class
work fine.
Table 8-3 lists the words that are reserved (and
hence off limits) in Python.
and |
del |
for |
Is |
raise |
assert |
elif |
from |
lamda |
return |
break |
else |
global |
not |
try |
class |
except |
if |
or |
while |
continue |
exec |
import |
pass |
yield[1] |
def |
finally |
in |
| |
[1] yield is an optional extension in Version 2.2, but is a standard keyword in 2.3. It is used in conjunction with generator functions, a newer feature discussed in Chapter 14. |
Python’s reserved words are always all lowercase.
And they are truly reserved; unlike names in the built-in scope that
you will meet in the next part, you cannot redefine reserved words by
assignment (e.g., and=1
is a syntax
error).[2] Furthermore, because module
names in import statements become variables in your script, this
constraint extends to your module filenames—you can code a file
called and.py, but cannot import it;
we’ll revisit this idea in Part V.
Besides these rules, there is also a set of
naming
conventions—rules which are not required,
but are used in normal practice. For instance, because names with two
leading and trailing underscores (e.g., __name__
) generally have special meaning to the Python
interpreter, you should avoid this pattern for your own names. Here
is a list of all the conventions Python follows:
Names that begin with a single underscore (_X
) are
not imported by a from
module import
*
statement (described in Chapter 16).
Names that have two leading and trailing underscores (__X__
) are system-defined names, which have special meaning to
the interpreter.
Names that begin with two underscores and do not end with two more
(__X
) are localized
(“mangled”) to enclosing classes
(described in Chapter 23).
The name that is just a single underscore (_
)
retains the result of the last expression, when working
interactively.
In addition to these Python interpreter conventions,
we’ll meet other conventions that Python programmers
usually follow as well. In Part VI, for
instance, we’ll see class names commonly start with
an uppercase letter, and that the name self, though not reserved,
usually has a special role. And in Part IV,
we’ll study another class of names known as the
built-ins, which are predefined but not reserved
(and so can be reassigned: open=42
works, though
you might wish it didn’t).
It’s crucial to keep Python’s distinction between names and objects clear. As described in Section 4.6 in Chapter 4, objects have a type (e.g., integer, list), and may be mutable or not. Names (a.k.a. variables), on the other hand, are always just references to objects; they have no notion of mutability and have no associated type information, apart from the type of the object they happen to reference at a given point in time.
In fact, it’s perfectly okay to assign the same name to different kinds of objects at different times:
>>>x = 0 # x bound to an integer object
>>>x = "Hello" # Now it's a string.
>>>x = [1, 2, 3] # And now it's a list.
In later examples, you’ll see that this generic nature of names can be a decided advantage in Python programming.[3] In Part IV, you’ll learn that names also live in something called a scope, which defines where they can be used; the place you assign a name determines where it is visible.
Beginning with Python 2.0, a set of additional assignment statement formats, listed in Table 8-4, are now available. Known as augmented assignment , and borrowed from the C language, these formats are mostly just shorthand. They imply the combination of a binary expression and an assignment. For instance, the following two formats are now roughly equivalent:
X = X + Y # Traditional form X += Y # Newer augmented form
Augmented assignment works on any type that supports the implied binary expression. For example, here are two ways to add 1 to a name:
>>>x = 1
>>>x = x + 1 # Traditional
>>>x
2 >>>x += 1 # Augmented
>>>x
3
When applied to a string, the augmented form performs concatenation
instead—exactly as if you had typed the longer: S = S
+ "SPAM
“:
>>>S = "spam
" >>>S += "SPAM" # Implied concatenation
>>>S
'spamSPAM'
As shown in Table 8-4, there are analogous
augmented assignment forms for every Python binary expression
operator (an operator with values on the left and right side). For
instance, X*=Y
multiplies and assigns,
X>>=Y
shifts right and assigns, and so on.
X //= Y
(for floor division) is new in Version
2.2. Augmented assignments have three advantages:[4]
There’s less for you to type. Need we say more?
They only need to evaluate the left side once. In X+=Y
, X
could be a
complicated object expression. In the augmented form, it need only be
evaluated once. In the long form, X=X+Y
,
X
appears twice, and must be run twice.
They automatically choose the optimal technique. For objects that support in-place changes, the augmented forms automatically perform in-place change operations, instead of slower copies.
The last point here requires a bit more explanation. For augment
assignments, in-place operations may be applied for mutable objects
as an optimization. Recall that lists can be extended in a variety of
ways. To add a single item to the end of a list, we can concatenate
or append
:
>>>L = [1, 2]
>>>L = L + [3] # Concatenate: slower
>>>L
[1, 2, 3] >>>L.append(4) # Faster, but in-place
>>>L
[1, 2, 3, 4]
And to add a set of items at the end, we may either concatenate
again, or call the list extend
method:[5]
>>>L = L + [5, 6] # Concatenate: slower
>>>L
[1, 2, 3, 4, 5, 6] >>>L.extend([7, 8]) # Faster, but in-place
>>>L
[1, 2, 3, 4, 5, 6, 7, 8]
In all of these, concatenation is less prone to the side effects of shared object references, but will generally run slower than the in-place equivalent. Concatenation must create a new object, copy in the list on the left, and then copy in the list on the right. By contrast, in-place method calls simply add items at the end of a memory block.
When augmented assignment is used to extend a list, we can forget
these details—Python automatically calls the quicker
extend
method, instead of the slower concatenation
operation
implied
by +
:
>>>L += [9, 10] # Mapped to L.extend([9, 10])
>>>L
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In Python, you can use expressions as statements too. But since the result of the expression won’t be saved, it makes sense to do so only if the expression does something useful as a side effect. Expressions are commonly used as statements in two situations:
Some functions and methods do lots of work without returning a value. Since you’re not interested in retaining the value they return, you can call such functions with an expression statement. Such functions are sometimes called procedures in other languages; in Python, they take the form of functions that don’t return a value.
Python echoes back the results of expressions typed at the interactive command line. Technically, these are expression statements too; they serve as a shorthand for typing print statements.
Table 8-5 lists some common expression statement forms in Python. Calls to functions and methods are coded with zero or more argument objects (really, expressions that evaluate to objects) in parentheses, after the function or method.
Operation |
Interpretation |
|
Function calls |
|
Method calls |
|
Interactive print |
|
Compound expressions |
|
Range tests |
The last line in the table is a special form: Python lets us string
together magnitude comparison tests, in order to code chained
comparisons such as range tests. For instance, the expression
(A < B < C)
tests whether
B
is between A
and
C
; it’s equivalent to the Boolean
test (A < B and B < C)
but is easier on the
eyes (and keyboard). Compound expressions aren’t
normally written as statements, but it’s
syntactically legal to do so and can even be useful at the
interactive prompt if you’re not sure of an
expression’s result.
Beware that although expressions can appear as statements in Python,
statements can’t be used as expressions. For
instance, Python doesn’t allow us to embed
assignment statements (=
) in other expressions.
The rationale for this is that it avoids common coding mistakes; you
can’t accidentally change a variable by typing
=
when you really mean to use the
==
equality test. You’ll see how
to code around this when you meet the Python while
loop in Chapter 10.
The
print
statement simply prints objects.
Technically, it writes the textual representation of objects to the
standard output stream. The standard output stream is the same as the
C language’s stdout
; it is
usually mapped to the window where you started your Python program
(unless redirected to a file in your system’s
shell).
In Chapter 7, we also saw file methods that write
text. The print
statement is similar, but more
focused: print
writes objects to the
stdout
stream (with some default formatting), but
file write methods write strings to files. Since the standard output
stream is available in Python as the stdout
object
in the built-in sys
module (i.e.,
sys.stdout
), it’s possible to
emulate print
with file writes, but
print
is easier to use.
Table 8-6 lists the
print
statement’s forms. We’ve seen the
basic print
statement in action already. By
default, it adds a space between the items separated by commas, and
adds a linefeed at the end of the current output line:
>>>x = 'a'
>>>y = 'b'
>>>print x, y
a b
Operation |
Interpretation |
|
Print objects to |
|
Same, but don’t add newline at end of text. |
|
Send text to |
This formatting is just a default; you can choose to use it or not.
To suppress the linefeed (so you can add more text to the current
line later), end your print
statement with a
comma, as shown in the second line of Table 8-6.
To suppress the space between items, you can instead build up an
output string yourself using the string concatenation and formatting
tools covered in Chapter 5, and print the string
all at once:
>>>print x + y
ab >>>print '%s...%s' % (x, y)
a...b
To print a hello world message, you simply print it:
>>> print 'hello world' # Print a string object.
hello world
Since expression results are echoed in the interactive command line,
you often don’t even need to use a
print
statement there; simply type expressions
you’d like to have printed and their results are
echoed back:
>>> 'hello world' # Interactive echoes
'hello world'
Really, the print
statement is just an ergonomic
feature of Python—it provides a user-friendly interface to the
sys.stdout
object, with a bit of default
formatting. You can also code print operations this way:
>>>import sys # Printing the hard way
>>>sys.stdout.write('hello world ')
hello world
This code explicitly calls the write
method of
sys.stdout
—an attribute preset when Python
starts up to an open file object connected to the output stream. The
print
statement hides most of those details. It
provides a simple tool for simple printing tasks.
The sys.stdout
print
equivalent
turns
out to be basis of a common technique in Python. In general, print
and sys.stdout
are related as follows:
print X
is equivalent to the longer:
import sys sys.stdout.write(str(X) + ' ')
that manually performs a string conversion with
str
, adds a newline with +
, and
calls the output stream’s write
method. The long form isn’t all that useful for
printing by itself. However, it is useful to know that this is
exactly what print
statements do, because it is
possible to reassign sys.stdout
to something
different than the standard output stream. In other words, this
equivalence provides a way for making your print
statements send their text to other places. For example:
import sys sys.stdout = open('log.txt', 'a') # Redirects prints to file ... print x, y, x # Shows up in log.txt
Here, we reset sys.stdout
to a manually-opened
output file object opened in append mode. After the reset, every
print
statement anywhere in the program will write
its text to the end of file log.txt
, instead of
the original output stream. The print
statements
are happy to keep calling
sys.stdout
’s
write
method, no matter what
sys.stdout
happens to refer to.
In fact, as this chapter’s
sidebar
on print
and stdout
will
explain, we can even reset sys.stdout
to nonfile
objects, as long as they have the expected protocol (a
write
method); when those objects are classes,
printed text can be routed and processed arbitrarily.
This trick of redirecting printed
text
by
assigning sys.stdout
was so commonly used that
Python’s print
statement has an
extension to make it easier. One potential problem with the last
section’s code is that there is no direct way to
restore the original output stream, should you need to switch back
after printing to a file. We can always save and restore as
needed:[6]
import sys temp = sys.stdout # Save for restoring. sys.stdout = open('log.txt', 'a') # Redirects prints to file ... print x, y, x # Print to file. ... sys.stdout = temp print a, b, c # Print to original stdout.
But this is just complicated enough that a print
extension was added to make the save and restore unnecessary. When a
print
statement begins with a
>>
followed by an output file (or other)
object, that single print
statement sends its text
to the object’s write
method, but
does not reset sys.stdout
. Because the redirection
is temporary, normal print
statements keep
printing to the original output stream:
log = open('log.txt', 'a') print >> log, x, y, z # Print to a file-like object. print a, b, c # Print to original stdout.
The >>
form of the print
is handy if you need to print to both files and the standard output
stream. If you use this form, be sure to give it a file object (or an
object that has the same write
method as a file
object), not a file’s name string.
[2] In the Jython Java-based implementation or Python, though, user-defined variables can sometimes be the same as Python reserved words.
[3] If you’ve used C++, you
may be interested to know that there is no notion of
C++’s const
declaration in
Python; certain objects may be immutable, but names can always be
assigned. Python also has ways to hide names in classes and modules,
but they’re not the same as C++’s
declarations.
[4] C/C++ programmers take note: although Python now has things
like X+=Y
, it still does not have
C’s auto-increment/decrement operators (e.g.,
X++
, --X
). These
don’t quite map to the Python object model, because
there is no notion of an in-place change to immutable objects like
numbers.
[5] As suggested in Chapter 6, we can also use
slice assignment: L[len(L):] = [11,12,13]
, but
this works roughly the same as the simpler list extend method.
[6] We can also use the relatively new __stdout__
attribute in module sys
,
which refers to the original value sys.stdout
had
at program start-up time. We still need to restore
sys.stdout
to sys.__stdout__
to go back to this original stream value, though. See the
sys
module in the library manual for more
details.