Chapter 8. Assignment, Expressions, and Print

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:

  1. Programs are composed of modules.

  2. Modules contain statements.

  3. Statements contain expressions.

  4. 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.

Table 8-1. Python statements

Statement

Role

Example

Assignment

Creating references

curly, moe, larry = 'good', 'bad', 'ugly'

Calls

Running functions

stdout.write("spam, ham, toast ")

print

Printing objects

print 'The Killer', joke

if/elif/else

Selecting actions

if "python" in text: print text

for/else

Sequence iteration

for x in mylist: print x

while/else

General loops

while 1: print 'hello'

pass

Empty placeholder

while 1: pass

break, continue

Loop jumps

while 1: if not line: break

try/except/ finally

Catching exceptions

try: action( )

except: print 'action error'

raise

Triggering exception

raise endSearch, location

import, from

Module access

import sys; from sys import stdin

def, return, yield

Building functions

def f(a, b, c=1, *d): return a+b+c+d[0]def gen(n): for i in n, yield i*2

class

Building objects

class subclass: staticData = [ ]

global

Namespaces

def function( ): global x, y; x = 'new'

del

Deleting references

del data[k]; del data[i:j]; del obj.attr

exec

Running code strings

exec "import " + modName in gdict, ldict

assert

Debugging checks

assert X > Y

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.

Assignment Statements

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.

Table 8-2. Assignment statement forms

Operation

Interpretation

spam = 'Spam'

Basic form

spam, ham = 'yum', 'YUM'

Tuple assignment (positional)

[spam, ham] = ['yum', 'YUM']

List assignment (positional)

spam = ham = 'lunch'

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:

Tuple and list unpacking assignments

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.

Multiple-target assignments

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.

Variable Name Rules

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:

Syntax: (underscore or letter) + (any number of letters, digits, or underscores)

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.

Case matters: SPAM is not the same as spam

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.

Reserved words are off limits

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.

Table 8-3. Python reserved words
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
print

[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.

Naming conventions

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).

Names have no type, but objects do

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.

Augmented Assignment Statements

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
Table 8-4. Augmented assignment statements
X += Y
X &= Y
X -= Y
X |= Y
X *= Y
X ^= Y
X /= Y
X »= Y
X %= Y
X «= Y
X **= Y
X //= Y

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]

Expression Statements

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:

For calls to functions and methods

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.

For printing values at the interactive prompt

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.

Table 8-5. Common Python expression statements

Operation

Interpretation

spam(eggs, ham)

Function calls

spam.ham(eggs)

Method calls

Spam

Interactive print

spam < ham and ham != eggs

Compound expressions

spam < ham < eggs

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.

Print Statements

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
Table 8-6. Print statement forms

Operation

Interpretation

print spam, ham

Print objects to sys.stdout; add a space between.

print spam, ham,

Same, but don’t add newline at end of text.

print >> myfile, spam, ham

Send text to myfile.write, not to sys.stdout.write.

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

The Python “Hello World” Program

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.

Redirecting the Output Stream

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.

The print>>file extension

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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset