python重写我的列表元素

2024-06-07 15:59:38 发布

您现在位置:Python中文网/ 问答频道 /正文

对python相当陌生,对python类非常陌生。这个问题有点牵连。非常感谢您的耐心:

我有一个班“星”。很简单。属性x、v和质量。另一个类,Galaxy,有一个属性“stars”,它只是一个恒星对象的列表:

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更新“stars”的所有元素,然后返回“stars”:

^{pr2}$

现在,我试着开这个东西,把“星星”的各种更新存储在一个名为“历史”的列表中:

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被“重新指向”一个全新的内存位置,而a[0]继续指向旧的b。第二,b的内存被“编辑”,而a[0]仍然指向那个位置。在append之后,一个[1]也指向该位置。我现在有吗?在

我对python还不太熟悉,还在搞清楚“python”哲学。但对我来说,直接重新分配指针,而以更复杂的方式进行“深度复制”有点像我平时想做的事情。有人能启发我吗?再次感谢。在


Tags: self元素列表属性历史galaxy指向stars
3条回答

我认为值得注意的是,如果你有一个以上的星系,它们将共享相同的恒星。当你真的不相信这会让你。。。在

我猜你用一个__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添加到历史记录列表时,您需要copy.deepcopy

^{pr2}$

它不是更改或重写所有值,而是历史记录中的所有元素都指向同一个数组对象。您需要使用数组的副本按值赋值,而不是引用。在

这是因为stars列表是可变的-它是一个可变的变量。当您调用stars.append时,它不会创建新的列表-它只是简单地编辑现有列表。当您调用history.append(x)时,python不会创建x的新的、干净的副本—它假定您希望将“real”x放在history数组中。在

如果您想在每次迭代时复制列表的状态,有几个选项(请参见How to clone a list in python?)。在

^{} module将完成此操作。它同时提供“浅”和“深”拷贝-粗略地说,深度副本也试图复制在对象中找到的任何其他变量(例如,包含其他列表的列表),而浅副本只需向下一层:

以下是带有copy的浅拷贝:

import copy

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

深度复制:

^{pr2}$

对阵列进行切片是可行的,因为它总是将浅拷贝作为中间步骤:

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)))

相关问题 更多 >

    热门问题