Multidimensional list of classes - overwriting issue

耗尽温柔 提交于 2021-01-29 05:18:26

问题


I want to create a list of classes, but every time I change an element in the list, all class elements in the list are overwritten:

class TypeTest:
    def __init__(self):
    self.val = int()

data = list([TypeTest for _ in range(3)])

for i in range(3):
    data[i].val = i
    print([data[0].val, data[1].val, data[2].val])

At the end, I need a multidimensional array and will have a more complex class, but the issue is the same.


回答1:


TypeTest is a type; TypeTest() creates an instance of that type. You need

data = list([TypeTest() for _ in range(3)])

instead of

data = list([TypeTest for _ in range(3)])

In the latter case, you are just adding multiple copies of the same TypeTest to the list.

Indeed, if you print the memory address of your list elements, you will find that they're the same object:

>>> data = list([TypeTest for _ in range(3)])
>>> print([id(x) for x in data])
[140184769568224, 140184769568224, 140184769568224]

whereas

>>> data = list([TypeTest() for _ in range(3)])
>>> print([id(x) for x in data])
[4451998096, 4451996816, 4451996176]



回答2:


You are creating an array of class references, instead of object (instance) references, meaning that every element is pointing to the same thing - TypeTest class.

To create objects, just use

data = np.array([TypeTest() for _ in range(3)])

If for any reason you really need different classes, you will have to create a new one for every element by inheriting from the base class.




回答3:


You need to make new objects like this within array.

data = list([TypeTest() for _ in range(3)])



回答4:


You are using your class the wrong way. init() method should be used to accept arguments, which can be passed to your self.val variable on initialization. This way you don't need and additional loop to set the variable.

Imagine class like a blueprint, which you have to instantiate to get the real things, which can be used as elements of lists, etc.

>>> my_object = TypeTest()

or create list of objects:

>>> data = [TypeTest(value) for value in range(3)]



回答5:


Solution

Instantiate your class object inside the for loop (list comprehension). You were using list([...]). Just use [TypeTest() for _ in range(3)]

# instantiate your class object
data = [TypeTest() for _ in range(3)] # after correction

# The line were you had the problem
data = list([TypeTest() for _ in range(3)]) # before correction

Modified class definition

Use the __init__() method to specify the optional input val and its type (as int) and default value of 0. This will allow you to directly assign a value to the attribute, val during instantiation. Or, if you want, you can always update it later as well.

class TypeTest(object):

    def __init__(self, val: int=0, verbose: int=0):
        self.val = val
        self.verbose = verbose
        if self.verbose > 0:
            print(self)

    # include __repr__ in your class-def to print 
    # meaningful information about the class. 
    def __repr__(self):
        return '{}( val: {} )'.format(self.__class__.__name__, self.val)

Single Line Code (Streamlined)

With this change in place, your code could be streamlined to as single line instatntiation + assignment of val:

# This will also print the objects created
# as we are using the keyword parameter: 
#     verbose = 1
data = [TypeTest(val=i, verbose=1) for i in range(3)]

Output:

TypeTest( val: 0 )
TypeTest( val: 1 )
TypeTest( val: 2 )


来源:https://stackoverflow.com/questions/61851406/multidimensional-list-of-classes-overwriting-issue

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!