Re: [Tutor] mutable types

2010-11-02 Thread Steven D'Aprano

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


Re: [Tutor] mutable types

2010-11-02 Thread Knacktus

Am 02.11.2010 13:51, schrieb John:

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

In [69]: a = 10
"a" is a reference to an immutable object of type int with value 10. 
Somewhere in memory is an object of type int with value 10 stored. This 
object cannot be changed. "a" is just a name that references to the 
memory adress.

In [70]: G = {}
In [71]: G[0] = [a]
now, G[0] holds a reference to a mutable object of type list with an 
immutable object of type int with value 10 as its content. So, your list 
holds as item the memory adress of an object int with value 10. Your 
list knows nothing about other names (like "a"), that refer to the same 
adress in memory. You have handed over the object to the list (or memory 
adress of the object), not the name "a".

In [72]: G[1] = G[0]
In [73]: a = 20

Now, you've created a *new* immutable object of type int with value 20.
"a" now refers to the adress of the new integer object. "a" has 
forgotten everything about its former reference to the object of type 
int with value 10.
You have *not* changed the "old" object of type int with value 10. Your 
list in G[0] still holds the memory adress of the first int with value 10.

In [74]: G[1]
Out[74]: [10]
In [75]: G[0]
Out[75]: [10]

??
Now, if you would keep a reference to the list you've handed over to the 
dict, you could change the content of the list, as the list is mutable.


>>> a = [10]
>>> G = {}
>>> G[0] = a
>>> G[0]
[10]
>>> a[0] = 20
>>> G[0]
[20]

Take care of some operations that return a copy of the list:

>>> a = a[:]
Now, "a" refernces to a new list, which has also one item of type in 
with value 20. But it's not the same list as originally!

>>> a[0] = 30
Changing this new list ...
>>> G[0]
[20]
does not affect the list, we stored in the dict.

HTH,

Jan

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


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


[Tutor] mutable types

2010-11-02 Thread John
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]

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