为什么Python列表中的对象在使用默认构造函数创建时似乎是彼此的浅层副本?

时间:2018-04-06 15:17:48

标签: python python-3.x default-constructor

很抱歉这个笨重的标题,但我不知道如何最好地描述我遇到的问题。

我定义自己的类,然后使用默认构造函数创建对象列表(不传递任何参数)。稍后,当我想访问列表中的一个对象并调用函数方法时,所有列表元素的属性会同时更改为相同的值。看起来列表中的所有元素都是浅层副本。

现在,如果我通过将默认值显式地作为参数传递来创建对象,则列表元素的行为与预期一致,我可以在单个元素上调用该方法而不更改其他元素。

这种行为对我非常困惑和违反直觉,我想理解为什么会这样。

重现行为的最小示例如下所示:

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)

这种情况下的输出是

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.        ]

即使只在一个元素上调用该方法。相反,如果我将Particle()更改为Particle(np.array([0.,0.,0.])),则输出变为

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.]

这就是我想要的。现在我可以务实,只是接受这个语言的怪癖,但如果一个对象没有我可以传递给构造函数的参数,我该怎么办?

PS:我使用的是Python 3.6.4

0 个答案:

没有答案