-2

I have a doubt about storing a class variables in a second variable, in order to be called later. This is my code (simplified to be readable):

class Agent(object):
    def __init__(self):
        self.actual = []

class Play(object):

    def __init__(self):
        self.x = 0.45 * 400
        self.y = 0.5 * 400
        self.position = []
        self.position.append([self.x, self.y])
        self.x_change = 20
        self.y_change = 0

    def do_move(self, move, x, y):
        move_array = [self.x_change, self.y_change]

        if move == 1 and self.x_change == 0:  # right
            move_array = [20, 0]
        self.x_change, self.y_change = move_array
        self.x = x + self.x_change
        self.y = y + self.y_change

        self.update_position(self.x, self.y)

    def update_position(self, x, y):
        self.position[-1][0] = x
        self.position[-1][1] = y


def run():
    agent = Agent()
    player1 = Play()
    agent.actual = [player1.position]
    print(agent.actual[0])
    i = 1
    player1.do_move(i, player1.x, player1.y)
    print(agent.actual[0])

run()

>> [[180.0, 200.0]]
>> [[200.0, 200.0]]

This is what I cannot understand. Why, if agent.actual stores the player.position and it is not modified after agent.actual = [player1.position], its value actually changes between the two print()? I modify player.position, but not agent.actual, which means it should stay the same. I cannot figure this out!

EDIT: I tried, as suggested, with the following methods:

agent.actual = player1.position.copy()

agent.actual = player1.position[:]

agent.actual= list(player1.position)

import copy
agent.actual = copy.copy(player1.position)

agent.actual = copy.deepcopy(player1.position)

All these methods always return, as before, two different values:

>> [[180.0, 200.0]]
>> [[200.0, 200.0]]
maurock
  • 527
  • 1
  • 7
  • 22
  • 1
    `agent.actual` is a list containing *a reference to* another list, which is mutable. Changes to `player1.position` are therefore reflected in `agent.actual`. If you don't want that behaviour, see the dupe for how to create a copy instead. – jonrsharpe Jul 24 '18 at 15:15
  • Thank you, finally I understand it. Sorry for duplicating, I did it because of my ignorance about Python making a reference instead of a copy, not because I didn't looked it up accurately. – maurock Jul 24 '18 at 15:26
  • @jonrsharpe I tried as suggested in the question you mentioned, but as you can read in my EDIT the results are not different. – maurock Jul 24 '18 at 18:43

1 Answers1

0

Player.position is list, which means it's mutable type. If you put this list in another list, Python makes a reference to it, not a copy.

When you add/delete/change items in the list, it will change everywhere the reference is hold.

You need to make a copy when you assign to agent.actual. Look at the copy module in Python or restructure your code (Hint: tuple is immutable type)

Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • Thank you, As you can see in my EDIT, I tried what you suggested with the `copy` module, but it doesn't work. – maurock Jul 24 '18 at 18:50
  • @MauroComi don't hold positions in list, use tuples. Copying lists will cause troubles in corner cases. Tuples are immutable. – Andrej Kesely Jul 24 '18 at 18:52