Understanding Python assignment

Here’s a quick question I often ask students in my Python classes:

>>> x = 100
>>> y = x
>>> x = 200

After executing the above code, what is the value of y?

The answer:

>>> print(y)

Many of my students, especially those with a background in C, are surprised. Didn’t we say that “y = x”? Thus, shouldn’t a change in x be reflected by a similar change in y?

Obviously not. But why is this the case?

Assignment in Python means one thing, and one thing only: The variable named on the left should now refer to the value on the right.

In other words, when I said:

y = x

Python doesn’t read this as, “y should now refer to the variable x.” Rather, it read it as, “y should now refer to whatever value x refers to.”

Because x refers to the integer 100, y now refers to the integer 100. After these two assignments (“x = 100” and “y = x”), there are now two references to the integer 100 that didn’t previously exist.

When we say that “x = 200”, we’re removing one of those references, such that x no longer refers to 100. Instead, x will now refer to the integer 200.

But y’s reference remains in place to where it was originally pointing, to 100. And indeed, the only way to change what y is referring to is via … assignment.

Think of this as assignment inertia: Without a new and explicit assignment, a variable will continue to refer to whatever it referred to previously.

Thus, while Python does have references (i.e., variables pointing to objects), it doesn’t have pointers (i.e., variables pointing to other variables). That’s a big difference, and one that makes the language easier to understand. But references can still be a bit tricky and confusing, especially for newcomers to the language.

Remember also that in an assignment, the right side is evaluated before the left side. By the time the left-hand-side is being assigned, any variables on the right-hand-side are long gone, replaced by the final value of the expression. For example:

>>> a = 10
>>> b = 20
>>> c = 30
>>> d = a + b * c

When we assign a value to the variable “d” above, it’s only after Python has evaluated “a + b * c”. The variables are replaced by the values to which they refer, the operations are evaluated, and the final result (610) is then assigned to “d”. “d” has no idea that it was ever getting a value from “a”, “b”, or “c”.

  • Siamack says:

    I think it is the other way around. In C/C++ assignment basically copies the value. In fact, this is what confuses me:
    >>> x = [100]
    >>> y = x
    >>> x.append(200)
    >>> y
    [100, 200]

  • Adam says:

    Furthermore, Python objects work exactly the way your students apparently think integers work in C:

    >>> class Something(object):
    … pass

    >>> x = Something()
    >>> y = Something()
    >>> x.value = 100
    >>> y = x
    >>> x.value = 200
    >>> print(y.value)

    I think I’m missing the point?

    • reuven says:

      I don’t have a good answer, except that this question routinely trips them up and surprises them.

      • Winfried Wilcke says:

        I’m totally new to Python and very confused with assignments. This snippet below produces totally unexpected result:

        #b1 and q1 are (numpy) one-dimensional arrays, b1 was #previously filled with random integers, either 0 or 1

        #printing out b1 now shows that b1[2]=0

        if (b1[2] == 0):
        # now printing q1 and b1 shows that b1[2] has now ALSO changed from 0 to 22 !! How is this possible?!

        help greatly appreciated, I have been chewing on this for hours now.. Winfried

        • Ivan says:

          In python, as it’s said above “y=x” tells that x and y are now pointing at the same piece of data in memory. And while new assignment to either x or y, removes this connection, other commands, like append, assigning to an element of x, etc do not change fact that x and y are referring to same data. So changing either of them this way will change other one too

  • Adam says:

    What kind of C has your students learned?

    $ cat test.c

    int main(void) {
    int x, y;
    x = 100;
    y = x;
    x = 200;
    printf(“%dn”, y);
    $ gcc -Wall -o test test.c
    $ ./test

    • reuven says:

      I must admit, maybe that I was just using the opportunity to make a swipe at C… my students tend to come from a C, C++, C#, and Java background, and my experience with those languages is far, far from fluent. So I figured that the confusion was the result of their C backgrounds. Maybe they’re just confused? I dunno!

      • Adam says:

        If you start by saying “in Python everything is objects”, then they might be thinking “I’ve learned that objects are assigned by reference”, and thus reach the wrong answer? Hard to tell!

  • >