Search code examples
pythonpython-3.xlistobjectdel

list attribute of object gets changed when calling del on a different attribute


I am confused by the behaviour of the following code:

data = [0,1,2,3,4,5]

class test():
  def __init__(self,data):
   self.data=data
   self.data2=data

  def main(self):
    del self.data2[3]

test_var = test(data)
test_var.main()
print(test_var.data)
print(test_var.data2)

what i would think should come out is this:

[0,1,2,3,4,5]
[0,1,2,4,5]

what i get is this:

[0,1,2,4,5]
[0,1,2,4,5]

Why is an element from the second list getting deleted when its not directly changed? Or does python handle attributes in such a way that this happens normally?

So how should i change the code that i get what i want?


Solution

  • Lists are mutable in Python and passed by reference. Whenever you assign it or pass it as an argument, a reference to it is passed and not a copy. Hence the outcome you're seeing. If you really want to mutate it, you need to deepcopy it.

    import copy
    
    class test():
    
        def __init__(self, data):
            self.data = copy.deepcopy(data)
            self.data2 = copy.deepcopy(data2)
    
    # if the list is going to be flat and just contain basic immutable types,
    # slicing (or shallow-copy) would do the job just as well.
    
    class test():
    
        def __init__(self, data):
            self.data = data[::] # or data[:] for that matter as @Joe Iddon suggested
            self.data2 = data[::]
    

    Note: not all types of objects support "deep-copying".