[英]python over-writing my list elements
对python来说是相当新的,对python类来说是非常新的。 问题涉及其中。 最感谢您的耐心:
我有一堂课“明星”。 很简单。 属性x,v和mass。 另一个类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]))
Galaxy还具有称为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被“重新指向”到一个全新的存储位置,而a [0]继续指向旧的b。 在第二个中,b处的内存被“编辑”,而a [0]仍指向该位置。 追加之后,a [1]也指向该位置。 我现在有吗?
我对python还是很陌生,但仍在弄清楚“ pythonic”的哲学。 但是对我来说,直接完成指针的重新分配,但是以更复杂的方式完成“深层复制”,这比我通常想要做的事情有些倒退。 谁能启发我? 再次感谢。
我认为值得注意的是,如果您拥有多个星系,它们将共享相同的恒星。 这可能会使您相信,当您并非如此时,您会覆盖您的星星。
我猜想使用__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]))
在这里,我将class属性 stars
转换为instance属性 。 现在,每个实例将拥有自己的stars
列表,而不是与宇宙中所有其他星系共享一个stars
列表。
正如其他人指出的那样,您的history
列表将遇到类似的问题(您对同一列表有多个引用)。 但是,此修复程序实际上取决于您在self.velstep
和self.xstep
。 如果在适当位置修改Star
对象,那么简单的(浅)列表副本将gal.time_stepper(0.1)[:]
例如gal.time_stepper(0.1)[:]
)。 (您将创建一个新列表,但它将包含不断更新的相同星星)。 在这种情况下,当您追加到历史记录列表时,将需要copy.deepcopy
:
history=[]
for n in range(100):
history.append(copy.deepcopy(gal.time_stepper(.1)))
这是因为stars
列表是可变的-它是一个可变变量。 当您调用stars.append
,它不会创建新列表-而是简单地编辑现有列表。 当你骂history.append(x)
蟒蛇不会创建一个新的,干净的副本x
-它假定你想要的“真正的” x
被放置在在history
阵列。
如果您想在每次迭代时复制列表的状态,则有几个选项(请参阅如何在python中克隆列表? )。
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
上调用list
-此类型转换式操作始终返回一个新的列表对象(再次,浅表):
history = []
for n in range(100):
history.append(list(gal.time_stepper(.1)))
它并没有更改或覆盖所有值,而是历史记录中的所有元素都指向同一数组对象。 您需要使用数组的副本按值分配引用,而不是引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.