Sorry for the bulky title, but I don't know how to best describe the kind of problem I'm encountering.
I define my own class and then create a list of objects with the default constructor (without passing any arguments). Later, when I want to access one of the objects in the list and call a function method, the properties of all list elements are changed at the same time and to the same values. It looks like all elements in the list are shallow copies.
Now if I create the objects by passing the default value explicitly as an argument, the list elements behave as expected and I can call the method on individual elements without changing the others.
This behavior is extremely puzzling and counterintuitive to me and I would like to understand why this happens.
A minimal example to reproduce the behavior looks as follows:
import numpy as np
L = 10.
# define Particle object
class Particle(object):
def __init__(self, position=np.array([0.,0.,0.]) ):
self.position = position
def propagate(self):
x = np.random.exponential(scale=L) # sample mean free path
self.position += np.array([x,0.,0.])
# initialize particle list
particles = 5
particle_list = []
for i in range(0, particles+1):
p = Particle() # <- this does not work as expected!
#p = Particle(np.array([0.,0.,0.])) # <- but this does!
particle_list.append(p)
# testing
print("after creation")
print(particle_list[0].position)
print(particle_list[1].position)
print(particle_list[2].position)
print(particle_list[3].position)
print(particle_list[4].position)
particle_list[2].propagate()
print("after propagation of 1 particle")
print(particle_list[0].position)
print(particle_list[1].position)
print(particle_list[2].position)
print(particle_list[3].position)
print(particle_list[4].position)
The output in this case is
after creation
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
after propagation of 1 particle
[1.19354594 0. 0. ]
[1.19354594 0. 0. ]
[1.19354594 0. 0. ]
[1.19354594 0. 0. ]
[1.19354594 0. 0. ]
even though the method has only be called on one element. Instead, if I change Particle()
to Particle(np.array([0.,0.,0.]))
the output becomes
after creation
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
after propagation of 1 particle
[0. 0. 0.]
[0. 0. 0.]
[7.55848724 0. 0. ]
[0. 0. 0.]
[0. 0. 0.]
which is what I want. Now I could be pragmatic and just accept this as a quirk of the language, but what do I do if an object does not have arguments I could pass to the constructor?
PS: I'm using Python 3.6.4