next up previous contents
Next: Indentation Up: Programming Previous: Programming   Contents


Assignments

One of the basic operations in any computer language is the assignment statement. The assignment statement allows us to associate a variable name with a value, so we can more easily manipulate our data. In python, like many other languages, the equal sign (=) is used to assign a value to a variable; the variable name is put on the left hand side of the equal sign, and the value (any valid python expression) is put on the right hand side of the equal sign. Some simple examples of assignment statements follow:
>>> x = 3
>>> y = 'This is a string'
>>> z = x + 3
>>> y = abs(-7)
>>> vegies = ['broccoli','peas','carrots']      
>>> meal = vegies
Assignment statements can be chained; if you need to set several variables to the same value, you can simply extend the assignment to each of the variables in a single statement:
>>> count = number = check = 0
All three variables (count, number, and check) will have the value 0 after this assignment. Note that, when using the python interpreter interactively, these assignment statements don't produce any output. (Of course, you can simply type the name of any variable of interest, and its value will be displayed in interactive mode.)

Another handy feature of the assignment operator in python is that it supports multiple assignments. If you have a comma separated list of variables on the left hand side of the equal sign, and an equal number of comma separated expressions on the right hand side, python assigns each variable to its corresponding expression:

>>> zero,one,ten = 0,1,10     
>>> all = first,last = ['john','smith']
The second example shows how the ideas of chaining and multiple assignment can be combined; the variable first has the value ``john'', second has the value ``smith'', and all is a list containing the two values. This sort of technique can be used with any expression that evaluates to a sequence (string, list or tuple).

While the internal details of python should usually not concern you, there is one aspect of the assignment statement which needs to be understood to program effectively in python. Consider the following assignment statements:

# assignment of values
>>> x = 3
>>> z = x + 4
>>> breakfast = 'spam'
>>> names = ['Fred','Sam','Harry']
# assignments using variables
>>> friends = names
>>> y = x
>>> meal = breakfast

In the first set of assignments, the values for the assignment consisted of literal strings, numbers or lists, or expressions involving such quantities. In these cases, those values are stored in memory, and will be associated with their assigned names until you actively change them, or python is finished with your program.

But when you make assignments of one variable name to another, python actually stores a reference to the variable, that is, instead of creating a new copy of the contents of the original variable, it stores information about where the original variable is stored, and, when the new variable is later referenced, it goes back to this location to find the value of the variable. Thus, the statement

>>> x = 3
tells python to store the integer value 3 in a location associated with the variable name x, but the statement
>>> y = x
tells python to store the location of the variable x in the variable y, and to use the value stored at that location as the value of y. This is one of several design features of python that help to keep the language efficient. To prevent you from losing your data, python keeps track of how many times a variable is referenced, and, if you change the value of a variable to which another variable has a reference, it copies the variable's value before it destroys it, so that the variable referencing it will continue to have the value you would expect it to have.

With scalar variables, it would be difficult to construct a situation where this scheme would produce surprising results, since once a reference's value is changed, python automatically updates the values of any variables which were referring to that value. With mutable objects such as lists, however, changes within the list do not initiate this updating mechanism, and surprising results can occur.

To illustrate, suppose we create a scalar variable, and assign it to a second variable:

>>> sound = 'Ni'
>>> knight = sound
If we change the value of the variable sound, python will update the value of knight so that the value is not lost:
>>> sound = 'Arf'
>>> sound
'Arf'
>>> knight
'Ni'

Now consider the case of a list. We'll create a list, then assign it to another variable:

>>> foods = ['spam','spam','spam','sausage','spam']
>>> meal = foods
If we assign an entirely new value to foods, python will update the value of meal so that it contains the original list, since it is now the only variable refering to that original list:
>>> foods = ['beans','spam','eggs']
>>> meal
['spam', 'spam', 'spam', 'sausage', 'spam']
But if we modify only part of the list, python will retain the reference so that meal will have the value of the modified list:
>>> foods = ['spam','spam','spam','sausage','spam']
>>> meal = foods
>>> foods[1] = 'beans'
>>> foods
['spam', 'beans', 'spam', 'sausage', 'spam']
>>> meal
['spam', 'beans', 'spam', 'sausage', 'spam']
Even though we didn't explicitly change any of the values stored through the name meal, you can see that meal is still refering to the (now modified) list stored under the name foods.

Python provides some tools to help you deal with this situation. The copy module (Section 8.9) provides a function called copy which will actually make a copy of a list, instead of simply storing a reference. Thus, if we wanted to insure that meal contained the original elements of foods even if foods got modified, we could invoke this function instead of using an assignment:

>>> import copy
>>> foods = ['spam','spam','spam','sausage','spam']
>>> meal = copy.copy(foods)
>>> foods[1] = 'beans'
>>> foods
['spam', 'beans', 'spam', 'sausage', 'spam']
>>> meal
['spam', 'spam', 'spam', 'sausage', 'spam']
A similar result can be obtained by assigning a slice of an array where no starting or ending index is provided. Instead of calling the copy function, we could have made a true copy of foods in meal with a statement like
>>> meal = foods[:]

The is operator can be used to find out if one variable is a reference to another. Like the logical equals operator (==, Section 6.3), the is operator returns 1 or 0 depending on whether or not the two objects being compared are actually references to the same thing. (The equals operator simply checks to see if they are of the same type, and contain the same values.) We can study the behavior of the is operator by inserting a few additional statements in the above example:

>>> foods = ['spam','spam','spam','sausage','spam']
>>> meal1 = foods
>>> meal2 = copy.copy(foods)
>>> foods == meal1
1
>>> foods is meal1
1
>>> foods == meal2
1
>>> foods is meal2
0                                                             
>>> foods[1] = 'beans'       
>>> foods == meal1
1
>>> foods is meal1
1
>>> foods == meal2
0
>>> foods is meal2
0
When a list is copied to another variable, its contents are identical to the original variable; thus the test for equality is true (i.e. 1). But since the contents of foods were actually copied to meal2, meal2 is not a reference to foods, and the is operator returns a false value (i.e. 0).


next up previous contents
Next: Indentation Up: Programming Previous: Programming   Contents
Phil Spector 2003-11-12