lists of variables

Alf P. Steinbach alfps at start.no
Fri Feb 26 15:44:44 EST 2010


* 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.



More information about the Python-list mailing list