John wrote:
Hello, I thought the following should end with G[1] and G[0] returning
20. Why doesn't it?

In [69]: a = 10
In [70]: G = {}
In [71]: G[0] = [a]
In [72]: G[1] = G[0]
In [73]: a = 20
In [74]: G[1]
Out[74]: [10]
In [75]: G[0]
Out[75]: [10]

This doesn't actually have anything to do with the difference between mutable and immutable objects. Here's a simpler example to think about:

a = 10  # the name "a" is bound to the object 10
b = a  # the name "b" is bound to the same object "a" is bound to
a = 20  # the name "a" is bound to the object 20
b = ????

What value would you expect b to have?

The fact that you are using a mutable dictionary in your example is no different:

a = 10  # the name "a" is bound to the object 10
G = {}  # the name "G" is bound to an empty dictionary object
G[0] = [a]  # the dictionary bound to G has a mapping added,
  # the key 0 is mapped to a list containing the object bound to "a"

The important thing here is that the list [a] doesn't, and can't, know anything about the *name* "a". All it sees is the object that a is *currently* bound to. Once that object is placed in the list, there is no connection from the name "a" to the list, or visa versa. So later on, when you re-bind "a" to 20, that does nothing to the object 10, or the list that contains 10, or the dict that contains the list.

Around this time, many people start arguing about "call by value" and "call by reference" (or sometimes "pass by value" and "pass by reference"). If these terms mean nothing to you, congratulations! That's one less thing for you to care about, and you can stop reading now and go and do something productive. Arguments about calling conventions in programming languages often sink into long, unproductive flame wars.

Seriously. Stop reading and go do some programming.

Still here? Okay, don't say you weren't warned...

If you do know the terms "call by (pass by) reference" and "call by value", and you're thinking that Python is pass-by-reference for mutable objects, no, it's not. There is no way to get this behaviour in Python, regardless of whether you use mutable or immutable objects:

# this doesn't work
a = 1
b = 2
swap(a, b)  # call a function with by-reference parameters
assert a == 2  # fails
assert b == 1  # also fails

Can't be done from Python. There are alternatives that work just as well, such as the idiomatic:

a, b = b, a

but Python has no by-reference variables or arguments.

Now you're thinking that Python must be pass-by-value. If you're not, congratulations, you've just dodged a very common mistake. Python isn't pass-by-value *either*:

def func(alist):
    del alist[:]
    return alist

# this doesn't work either
a = [1,2,3]
b = func(a)  # pass-by-value automatically makes a copy of a
assert a == [1,2,3] and b = []  # fails

Python's evaluation strategy goes by various names, my favourite being pass-by-object. Another is call-by-sharing. Unfortunately, other languages fall into the trap of thinking that there are only two strategies, call-by-value and call-by-reference, and so they use one or the other of those names for the exact same behaviour that Python exhibits. Sigh.

http://en.wikipedia.org/wiki/Evaluation_strategy




--
Steven
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to