* Michael Pardee:
I'm relatively new to python and I was very surprised by the following behavior:
'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.
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.
This changes what 'a' refers to.
It does not change what the first array element refers to.
[1, 2]
Whoah! Are python lists only for literals?
No, that's an irrelevant notion.
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.
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.
[{'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[{}, {'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.