蟒蛇过写我的列表元素(python over-writing my list elements)

2019-08-03 00:10发布

相当新的蟒蛇,很新的蟒蛇类。 问题是有点麻烦。 最欣赏你的耐心:

我有一类“明星”。 很简单。 属性X,V,和质量。 另一类,银河,有一个属性的“明星”这仅仅是一个明星的对象列表:

class Galaxy:

    numstars=0.
    stars=[]

    def __init__(self,numin,xes,vees,masses):
        self.numstars=numin
        for n in range(numin):
            self.stars.append(Star(xes[n],vees[n],masses[n]))

银河也有称为time_stepper的属性功能。 我只想说time_stepper刚刚更新的“明星”的所有元素,然后返回“明星”:

def time_stepper(self,dt):
    self.velstep(dt)
    self.xstep(dt)
    self.velstep(dt)
    return(self.stars)

现在,我正在努力推动这件事情,并存储在一个名为“历史”列表中的“明星”的各种更新:

gal=Galaxy(#stuff#)
history=[]
for n in range(100):
    history.append(gal.time_stepper(.1))

最后,我的问题:在这个循环中的每次迭代,“明星”的新元素被添加到“历史”,但...这是... ... 所有的历史以前的元素是通过编写和提供的相同的值作为历史的最新元素! 那么发生了什么? 我碰到的关于Python列出了以前我不明白的事情,但我想我终于有了它的绝对主力。 显然不是。 谢谢你的帮助。

附录:感谢大家的帮助。 没想到的是很多有用的回复,特别是这么快。 我的问题是,我是假设这两段代码基本上是相同的。 第一:

>>> a=[]
>>> b=[1,2,3]
>>> a.append(b)
>>> b=[4,5,6]
>>> a.append(b)
>>> a
[[1, 2, 3], [4, 5, 6]]

第二:

>>> a=[]
>>> b=[1,2,3]
>>> a.append(b)
>>> b[:]=(4,5,6)
>>> b
[4, 5, 6]
>>> a.append(b)
>>> a
[[4, 5, 6], [4, 5, 6]]

和哎呦! 他们不是。 因此,在码1,我猜,B是“重新尖”,以一个全新的存储位置,而[0]继续指向了老B。 在第二个,在B的存储的是“编辑”和一个[0]仍然指向该位置。 追加后,[1]也指向该位置。 我必须现在?

我很新的蟒蛇,现在还在搞清楚“Python化”的理念。 但对我来说,有直接了当指针的重新分配,而是一个“深拷贝”,在更复杂的方式来完成是有点向后从我平时想做事的方式。 任何人都可以告诉我吗? 再次感谢。

Answer 1:

我认为这是值得一提的是,如果你有超过1个星系,他们将共享相同的星星。 这可能会导致你相信你会覆盖你明星,当你真的不...

我猜你可能会用更好的__init__ ,看起来像:

def __init__(self,numin,xes,vees,masses):
    self.stars = []
    self.numstars = numin
    for n in range(numin):
        self.stars.append(Star(xes[n],vees[n],masses[n]))

在这里,我转移类属性 stars是一个实例属性 。 现在,每个实例都将有它自己的stars名单,而不是共享一个stars与所有在宇宙中其他星系的名单。

正如其他人指出,您的history列表会从类似的问题(你有相同的列表中选择多个引用)受苦。 然而,固定真的取决于你在做什么self.velstepself.xstep 。 如果修改了Star到位的对象,那么一个简单的(浅)名单副本不会给你带来任何好(如gal.time_stepper(0.1)[:] )。 (您将创建一个新的列表,但它会保持其不断更新同样星)。 在这种情况下,你要copy.deepcopy当你追加到历史列表:

history=[]
for n in range(100):
    history.append(copy.deepcopy(gal.time_stepper(.1)))


Answer 2:

这是因为stars名单是可变的-它是一个可变的变量。 当你调用stars.append ,它不会创建一个新的列表-它简单的编辑现有列表。 当你骂history.append(x)蟒蛇不会创建一个新的,干净的副本x -它假定你想要的“真正的” x被放置在在history阵列。

如果您想以列表的状态,在每次迭代复制,有几个选项(参见如何克隆Python的list? )。

copy模块就可以了。 它提供了“浅”和“深”的副本 - 粗略地说,深拷贝尝试,他们发现的任何其他变量也复制对象内(例如,其它链表),而浅的人只是去下一层:

下面是浅拷贝copy

import copy

history=[]
for n in range(100):
    history.append(copy.copy(gal.time_stepper(.1)))

而深副本:

import copy

history=[]
for n in range(100):
    history.append(copy.deepcopy(gal.time_stepper(.1)))

切片阵列将工作,因为它总是浅拷贝作为一个中间步骤:

history = []
for n in range(100):
    history.append(gal.time_stepper(.1)[:])

您也可以拨打list现有名单上-这类型转换式的操作总是返回一个新的列表对象(再次,浅):

history = []
for n in range(100):
    history.append(list(gal.time_stepper(.1)))


Answer 3:

它并没有改变或者重写所有的值,而是在所有历史点元素相同的数组对象。 您需要通过价值来分配通过使用数组的一个副本而不是引用。



文章来源: python over-writing my list elements