对列表元素的更新应用于整个列表 python

Updates to elements of list are applied to the whole list python

我正在尝试编写一个简单的程序来使用 python(和 pygame 用于 GUI 来模拟 N 体系​​统,因为我比 tk 更有经验)。我 运行 遇到的问题是我制作了一个主体 class,它是一个精灵的子 class。我有一个大小为 n 的自适应列表,它可以将那么多主体附加到列表中。首先,我决定在双 for 循环中执行更新,最后一个 for 循环在计算更新后传递更新(我知道这效率不高,不是重点)。我的问题是,当我将更新传递给此列表的元素时,更新将应用于该列表中的所有内容。这里发生了什么?为什么将这些完全独立的元素捆绑在一起?下面是必要的代码

正文class

class Body(Sprite):
    vel = Vector2(0,0)
    acc = Vector2(0,0)
    def __init__(self, x, y, size, mass, init_val = True, color=(255,255,0)):
        super().__init__()
        self.rect = Rect(x-size[0]/2,y-size[1]/2,size[0],size[1])
        self.mass = mass
        self.pos = Vector2(x,y)
        #self.vel = Vector2(random(),random())
        if init_val:
            self.acc = Vector2(random(),random())
        self.image = Surface(size)
        self.image.fill((255,255,255))
        self.image.set_colorkey((255,255,255))
        draw_circle(self.image,color,(size[0]/2,size[1]/2),size[0]/2)

    def update(self, force):
        self.acc += force
        self.vel += self.acc
        self.rect.move_ip(self.vel)

模拟循环

class nbody:
    def __init__(self, n = 3, screensize=(1366,768)):
        self.win = pg.display.set_mode(screensize)
        self.clock = pg.time.Clock()
        self.bodies = Group()
        sareax = [int(screensize[0]/4), int(screensize[0]*3/4)]
        sareay = [int(screensize[1]/4), int(screensize[1]*3/4)]
        c = [(255,0,0), (0,255,0), (0,0,255)]
        self.bodies = []
        for i in range(n):
            mass = 5 + random()*5
            size = [mass*2]*2
            self.bodies.append(Body(randint(sareax[0], sareax[1]),randint(sareay[0],sareay[1]),size,mass, init_val=False, color=c[i]))
    
    def run_sim(self, time=None, fps = 0.5):
        run = True
        while run:
            self.clock.tick(fps)
            self.win.fill((0,0,0))
            for e in pg.event.get():
                if e.type == pg.QUIT:
                    pg.quit()
                    quit()
                elif e.type == pg.KEYDOWN:
                    if e.key == pg.K_ESCAPE:
                        run = False
                elif e.type == pg.KEYUP:
                    NotImplemented
            updates = []
            for b1,i in zip(self.bodies,range(len(self.bodies))):
                df = Vector2(0,0)
                for b2,j in zip(self.bodies,range(len(self.bodies))):
                    if i != j:
                        temp = newton(GRAV_CONSTANT, b1, b2)
                        mag = Vector2(b2.rect.centerx-b1.rect.centerx, b2.rect.centery-b1.rect.centery)
                        mag.scale_to_length(temp)
                        df += temp*mag
                        #print("Body {} has force {} to body {}".format(i,temp*mag,j))
                        if pg.sprite.collide_mask(b1,b2):
                            b1.kill()
                            b2.kill()
                updates.append(df)
            print(updates)
            for bnum,up in zip(range(len(updates)),updates):
                print("Before:", self.bodies[bnum].rect.center, self.bodies[bnum].vel, self.bodies[bnum].acc)
                self.bodies[bnum].update(up)
                print("Change:", up)
                print("After:", self.bodies[bnum].rect.center, self.bodies[bnum].vel, self.bodies[bnum].acc)
                pg.draw.line(self.win, (255,255,0), self.bodies[bnum].rect.center, (20*up.normalize())+self.bodies[bnum].rect.center, width=2)
                self.win.blit(self.bodies[bnum].image,self.bodies[bnum].rect)
                
            pg.display.flip()
        
        return

参见Class and Instance Variables

Generally speaking, instance variables are for data unique to each instance and class variables are for attributes and methods shared by all instances of the class.

由于 valacc 是 class 属性,它们由所有 Body 对象共享,正如您在问题中提到的:“这些完全独立的元素捆绑在一起

velacc 必须是 instance attribute instead of class attributes:

class Body(Sprite):
    def __init__(self, x, y, size, mass, init_val = True, color=(255,255,0)):
        super().__init__()
        self.rect = Rect(x-size[0]/2,y-size[1]/2,size[0],size[1])
        self.mass = mass
        self.pos = Vector2(x,y)
       
        self.vel = Vector2(0,0)
        self.acc = Vector2(0,0)
        if init_val:
            self.acc = Vector2(random(),random())

        self.image = Surface(size)
        self.image.fill((255,255,255))
        self.image.set_colorkey((255,255,255))
        draw_circle(self.image,color,(size[0]/2,size[1]/2),size[0]/2)