0

I have TestData class where I want to store time, x, y info.

Then I have a GenericData class where I want two TestData instances saved as left and right.

I instantiate GenericData and I append a value to the left instance, but the right instance is also updated!

This means that when I call generic = GenericData(TestData(), TestData()) the two TestData() calls are instantiating the same object.

How can I instantiate two different TestData inside GenericData, so I can update them independently?

class GenericData:
    def __init__(self, left, right):
        self.left = left
        self.right = right

class TestData:
    def __init__(self, t=[], x=[], y=[]):
        self.t = t
        self.x = x
        self.y = y

generic = GenericData(TestData(), TestData())
generic.left.t.append(3)

print(generic.left.t)
print(generic.right.t)

[3]
[3]    <-- This one should be empty!
  • 1
    Common issue tied to how empty lists behave as default values in constructor call. Look it up on google. Basically the default value for `t` is generated once and stored in memory and all subsequent constructors refer to it instead of creating a new empty list. Can do smth like `def func(t=None):if t==None:t=[];self.t=t` instead. – IcedLance Jul 25 '19 at 10:18

2 Answers2

2

The left and right members of GenericData are two different objects, but they share the same list instances created as default arguments in TestData definition.

In [4]: id(generic.right) == id(generic.left)
Out[4]: False
In [5]: id(generic.right.t) == id(generic.left.t)
Out[5]: True

Because of that you should avoid mutable default arguments.

quamrana
  • 37,849
  • 12
  • 53
  • 71
zbusia
  • 571
  • 2
  • 7
1

Change this

class TestData:
    def __init__(self, t=[], x=[], y=[]):
        self.t = t
        self.x = x
        self.y = y

to this

class TestData:
    def __init__(self, t=None, x=None, y=None):
        if t is None:
            t = []
        if x is None:
            x = []
        if y is None:
            y = []
        self.t = t
        self.x = x
        self.y = y

Usually, when we use a list or dictionary as the default argument to a function, we want the program to create a new list or dictionary every time that the function is called. However, this is not what Python does. The first time that the function is called, Python creates a persistent object for the list or dictionary because functions in Python are first-class objects. Every subsequent time the function is called, Python uses that same persistent object that was created from the first call to the function.

Reference: https://effbot.org/zone/default-values.htm

bumblebee
  • 1,811
  • 12
  • 19