* Michael Pardee:
I'm relatively new to python and I was very surprised by the following behavior:

a=1
b=2

'a' refers to an object representing the integer 1.

Since 1 is an immutable value you can just as well think of it as 'a' containing the value 1, because a reference to an immutable value is for nearly all practical purposes indistinguishable from that value.

'b' refers to an object representing the integer 2, which, again, since integers are immutable, you can just as well think of as 'b' containing the value 2.


mylist=[a,b]

A 'list' object (an array) is constructed, and 'mylist' is set to refer to it. The array has two items. The first item is set to refer to same object as 'a' (a reference copy), the second item is set to refer to the same object as 'b'.

But since integers are immutable you can just as well think of it as a copying of the integer values.

Immutable values allow you to think of handling the values directly.


print mylist
[1, 2]
a=3

This changes what 'a' refers to.

It does not change what the first array element refers to.


print mylist
[1, 2]

Whoah!  Are python lists only for literals?

No, that's an irrelevant notion.


 Nope:

c={}
d={}

Here 'c' now refers to a dictionary object, which is mutable (can be changed).

And 'd' refers to another dictionary object.


mydlist=[c,d]
print mydlist
[{}, {}]

A 'list' array object is constructed, and 'mydlist' is set to refer to it.

The first item in the array is set to refer to the same object as 'c' refers to, namely a mutable dictionary object (currently an empty dictionary).

The second item in the array is set to refer to the same object as 'd' refers to, namely a mutable dictionary object (currently an empty dictionary).

It's the same that happened earlier with the integers.

The only difference, but it's a significant one, is that now the referred to objects are mutable, that is, they can be changed.


c['x']=1

The dictionary object referred to by 'c' is updated to now have a key 'x' with associated value 1.

In more gory detail: the key is associated with a reference to an object representing 1, but again, since integer values are immutable you can think of this as a direct association with the value; the reference view of this association is mostly[1] only relevant when the referred to object is mutable.

Since the dictionary object that you're changing is referred to by both 'c' and the first item of 'mydlist', both of these reflect the change.


print mydlist
[{'x': 1}, {}]

Yep.


So it looks like variables in a list are stored as object references.

You mean items in a list are references to objects. Yes.


This seems to confirm that:

mydlist[1]['y']=4
print mydlist
[{}, {'y': 4}]

To check that you should instead have printed 'd', where you'd also see the change, since 'd' refers to the same dictionary object as 'mydlist[1]' does.


So I figure my initial example doesn't work because if you assign a
literal to something it is changing the object.

No, it has nothing to do with literals.

With the current language definition[2], as of Python 2.x and 3.x, it's very simple: assignments copy references, and that's all they do.

References to immutable objects allow you to think of values being copied around, which except for checking the identities of those objects (seldom relevant) yields the exact same conclusions about the effect of operations, but that's only because those immutable objects never change.

What you did above was to copy references to mutable objects, objects that can change.

Then the value-copying view breaks down.


 But modifying a list
or dict (as long as you don't re-construct it) does not change the
object.

A simple way to think of this is copying references.

Objects are never copied by Python assignments.

The assignments only copy references.


I can think of some ways to work around this, including using single
element lists as "pointers":

aa=[1]
bb=[2]
myplist=[aa,bb]
print myplist
[[1], [2]]
aa[0]=3
print myplist
[[3], [2]]

This is the same as your last example above, except that now you're using 'list' arrays as the referred to mutable objects, instead of 'dict' dictionary objects.


But what would be "the python way" to accomplish "list of variables"
functionality?

Possibly, if you think of assignments as copying references, you won't need that notion.


Cheers & hth.,

- Alf

Notes:
[1] The reference view can be relevant also for immutable objects in (at least) two cases. One is when the program logic depends on object identity, obtainable via the id function, which is just bad programming, but I mention it for completeness. The other is where you have a really large immutable object, such as in Python 2.x a very large 'long' value; then assignments would be inefficient if the value was actually copied, but since assignments only copy references in Python you can blissfully disregard the size of the object with respect to assignments. :-) [2] Some wording in the language spec requires that an assignment behaves as if references were copied, including preservation of object identity. But object identity is almost never an issue for immutable objects, and a relaxation of that wording, for immutable values, might permit some optimization. So it just might change somewhen in the future, trading simplicity for some efficiency.
--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to