问题
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