Kent's Korner
by Kent S Johnson

2008-06-22 17:44:14

Assignment

Assignment in Python often confuses newcomers to the language. Why does this change the value of b?

>>> a = [1, 2, 3]
>>> b = a
>>> a[2] = 5
>>> b
[1, 2, 5]

But this does not?

>>> a = 10
>>> b = a
>>> a += 4
>>> b
10

Programmers coming from a background in C and C++ have a mental model of variables as containers for values. This model works in those languages, where variables correspond to memory locations and assignment copies a value from one location to another. It doesn't work in Python. To write correct Python programs you have to have a different model for what variables are and how they behave.

Python names are not containers for values, they are names (references) for values. Assignment creates a name or binds a new value to a name. Assignment never copies a value, it creates a new reference to the same value. Think of the name as pointing to the value, or as a sticky note attached to the value.

The assignment b = a binds b to the same value to which a is bound. After the assignment, a and b refer to the same value. The difference between the two examples above is in what happens after the initial assignment.

In the first example, a and b are both bound to a list, which is mutable - it can be changed in place. The assignment

a[2] = 5

changes the value of the referenced list in place. a and b still point to the same list, and the value of the list has changed.

In the second case, a and b both refer to the integer 10. Integers are immutable - their value cannot change. The statement a += 4 computes the integer 14 and binds a to the new value. b is not changed - it is still bound to the value 10.

Note: Internally, most namespaces - where name look up happens - are implemented as dictionaries. The names are the keys; the dictionary values are the values.

Parameter passing

Parameter passing has the same semantics as assignment - it binds a name in the local scope to the passed-in value. If you pass a list as a value and modify the list, the caller will see the modification. This may or may not be what you want; if you model parameter passing as copying values you will be surprised by this behaviour. If you take this behaviour to mean that values are passed "by reference", then you may be surprised when an assignment to the parameter name in a function doesn't affect the value at the caller. In other words, given this:

def f(x, y):
  x = 3
  y.append(1)

a = 5
b = []
f(a, b)

What are the current values of a and b? Without a correct model of parameter passing you will not know.

Pass by value or pass by reference?

A popular debate on comp.lang.python is over whether Python passes values by value or by reference. I'm no expert, but based on the meaning I learned for these term in C and C++, the answer is "neither".

If Python passed by value, then the function f() would not be able to change the value of b seen by the caller. (It does.)

If Python passed by reference, then f() would be able to change the value of a seen by the caller. (It can't.)

If you think of Python variables as references to values, then parameter passing can be seen as passing the reference by value. This is sometimes called "call by object reference" which seems as good a name as any.

Links

 
© Kent S Johnson Creative Commons License

Short, introductory essays about Python.

kentsjohnson.com

Kent's Korner home

Weblog

Other Essays