对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”哲学。但对我来说,直接重新分配指针,而以更复杂的方式进行“深度复制”有点像我平时想做的事情。有人能启发我吗?再次感谢。在
我认为值得注意的是,如果你有一个以上的星系,它们将共享相同的恒星。当你真的不相信这会让你。。。在
我猜你用一个
__init__
可能会更好,它看起来像:这里我将类属性
stars
转换为实例属性。现在每个实例都将拥有自己的stars
列表,而不是与宇宙中所有其他星系共享一个stars
列表。在正如其他人所指出的,您的
^{pr2}$history
列表也会遇到类似的问题(您对同一列表有多个引用)。但是,修复实际上取决于您在self.velstep
和self.xstep
中执行的操作。如果您在适当的地方修改Star
对象,那么一个简单的(浅的)列表副本对您没有任何好处(例如gal.time_stepper(0.1)[:]
)。(您将创建一个新的列表,但它将包含不断更新的相同的星星)。在这种情况下,当您将copy.deepcopy
添加到历史记录列表时,您需要copy.deepcopy
:它不是更改或重写所有值,而是历史记录中的所有元素都指向同一个数组对象。您需要使用数组的副本按值赋值,而不是引用。在
这是因为
stars
列表是可变的-它是一个可变的变量。当您调用stars.append
时,它不会创建新的列表-它只是简单地编辑现有列表。当您调用history.append(x)
时,python不会创建x
的新的、干净的副本—它假定您希望将“real”x
放在history
数组中。在如果您想在每次迭代时复制列表的状态,有几个选项(请参见How to clone a list in python?)。在
^{} module 将完成此操作。它同时提供“浅”和“深”拷贝-粗略地说,深度副本也试图复制在对象中找到的任何其他变量(例如,包含其他列表的列表),而浅副本只需向下一层:
以下是带有
copy
的浅拷贝:深度复制:
^{pr2}$对阵列进行切片是可行的,因为它总是将浅拷贝作为中间步骤:
您还可以对现有列表调用
list
-此类型转换操作始终返回一个新的列表对象(同样,浅显地):相关问题 更多 >
编程相关推荐