1

I was playing around with some code earlier, and I noticed something rather strange, and I haven't been able to explain it.

Below are two functions that are exactly the same except for one thing. The variable origionalPos is a list in the first function and a tuple in the second one.

def ticking_as_list():
    tick = False
    ticking = False
    originalPos = [0,0]
    pos = [0,0]

    x = 0
    RUNNING = True
    while RUNNING:
        x += 1
        if x % 50 == 0:
            tick = not tick
            ticking = not ticking

        if ticking:
            originalPos = pos
            ticking = False

        pos[0] = originalPos[0] + 10
        pos[1] = originalPos[1] + 10

        if x == 500:
            RUNNING = False
            print(pos)

def ticking_as_tuple():
    tick = False
    ticking = False
    originalPos = (0,0)
    pos = [0,0]

    x = 0
    RUNNING = True
    while RUNNING:
        x += 1
        if x % 50 == 0:
            tick = not tick
            ticking = not ticking

        if ticking:
            originalPos = (pos[0],pos[1])
            ticking = False

        pos[0] = originalPos[0] + 10
        pos[1] = originalPos[1] + 10

        if x == 500:
            RUNNING = False
            print(pos)

The functions are set to change the values of pos and add 10 to them every time x is divisible by 50 and print the result when it equals 500. There are far easier ways to do this I know, but that is not the subject of the question.

When I run either of these functions, I expected to get an output of [110,110] from both of them, however; when I actually ran them, the output is as follows:

>>> ticking_as_list()
[4520,4520]
>>> ticking_as_tuple()
[110,110]

The function with ticking as a list is obviously much higher than when it is a tuple. When I look at what is happening as each function executes by printing pos while each function executes, it shows that 10 is added to pos on every iteration while only after every 50th iteration when it is a tuple as it should.

Why is it that the list always updates even when the value ticking is equal to false? As shown in the code:

        if x % 50 == 0:
            tick = not tick
            ticking = not ticking

        if ticking:
            originalPos = pos
            ticking = False

ticking only becomes true when x is divisible by 50, and immediately becomes false afterward. Which should make originalPos only update when that is true, however; it doesn't. It does work correctly as a tuple value though. Why is this? If I had accidentally changed changed the value anywhere else, an error would be raised in the tuple function because because tuples are static, and if the logic in other parts of the function were off, the tuple function would output the same as the list function.

What is the reason this happens?

Flutterguy135
  • 468
  • 3
  • 10

3 Answers3

2

The line originalPos = pos does not make a new list, it only gives the existing list a new name. To create a new list, you can use an empty list slice.

originalPos = pos[:]

Edit: It looks like an explicit copy method was added in Python 3.3.

originalPos = pos.copy()
Community
  • 1
  • 1
Jared Goguen
  • 8,772
  • 2
  • 18
  • 36
1
    if ticking:
        originalPos = pos
        ticking = False

The second statement makes the variable originalPos reference the same list as pos, so from there on changing one also changes the other. You probably want to copy over the actual values in the pos, so take a look at this answer.

In short

originalPos = pos[:]

should work fine.

Community
  • 1
  • 1
Jan Christoph Terasa
  • 5,781
  • 24
  • 34
0

The difference is here:

originalPos = pos

You just use a reference, i.e. originalPos and pos are two names for the same object.

Change it to:

originalPos = pos[:]

and you get:

>>> ticking_as_list()
[110, 110]

This is the same result as for the tuple version.

Mike Müller
  • 82,630
  • 20
  • 166
  • 161