confused about Python assignment

Stephen Horne steve at ninereeds.fsnet.co.uk
Thu Oct 30 21:52:37 EST 2003


On 30 Oct 2003 17:49:18 -0800, flyfeather at myrealbox.com (Haoyu Zhang)
wrote:

>Dear Friends,
>Python assignment is a reference assignment. However, I really can't
>explain the difference in the following example. When the object is
>a list, the assignment seems to be a reference. However, when the 
>object is a number, the story is so different. I don't understantd
>for what reason Python deals with them differently. The example is
>as follows:

I've been confused by this in the past, but it turns out that there
isn't much to be confused about once you understand what is happening.

Python assignment binds the right-hand-side value to the
left-hand-side placeholder (variable, slot within list or whatever).
It doesn't affect whatever value used to be referenced by that
placeholder except in terms of Pythons internal garbage-collection
housekeeping.

This assignment is *ALWAYS* by reference, including with integers, but
with immutable values such as integers the by-reference thing isn't so
obvious.

It is hard to make this clear with integers (at least for simple
examples, there seems only ever to be one object with the value '1'
for instance) but it can be made obvious with floats, which are also
immutable...

>>> x=1.0
>>> y=x
>>> x is y
True

At this stage, x and y don't just have equivalent values - they refer
to exactly the same object.

>>> y=5.0
>>> y/=5
>>> y
1.0
>>> x is y
False
>>> x==y
True

At this stage, although the value of y is equal to the value of x,
these two values are held in different objects, at different locations
in memory.

Unlike a list, however, there is no way to modify the internals of a
float in-place - that is the whole point of being immutable - and so
the fact that the assignment does not make copies is unlikely to be
noticed unless you specifically look for it using the 'is' operator.

There is a significant error in the logic of your example...

>>>> a = [3, 2,1]
>>>> b = a
>>>> a,b
>([3, 2, 1], [3, 2, 1])
>>>> a[1]=0

The line above is an in-place modifier of the object.

>>>> a,b
>([3, 0, 1], [3, 0, 1])
>>>> c = 1 
>>>> d = c
>>>> c,d
>(1, 1)
>>>> c=0

The line above is an assignment to the variable, which doesn't care
about the object that variable previously referenced.

>>>> c,d
>(0, 1)

In other words, this code is comparing chalk with cheese. The
equivalent code using lists to compare to your integer example would
be...

>>> a=[3,2,1]
>>> b=a
>>> a,b
([3, 2, 1], [3, 2, 1])
>>> a=[3,0,1]
>>> a,b
([3, 0, 1], [3, 2, 1])

This comparison is fair because the same assignment method (simple
assignment of value to variable) is used for the second assignment to
a, just as is done in your integer code. An in-place modification
cannot be done to an integer because it is immutable, and so its use
in the list case is very much apples compared to oranges.

I'm not a big fan of this myself, and I've ended up making these same
mistakes a number of times in the past - though I think the point has
now been beaten in well enough for a lifetime. It can be difficult for
those of us who find copy semantics more intuitive. But really, I
suppose this is something most programmers will need to get used to -
it's not just Python that works like this, and the pattern seems to be
catching on as higher level languages get more popular. For example,
C# and Java - both supposed to be higher level replacements for C++ -
have similar semantics for assignments with all class instances and
most non-basic types.


-- 
Steve Horne

steve at ninereeds dot fsnet dot co dot uk




More information about the Python-list mailing list