简体   繁体   English

python覆盖我的列表元素

[英]python over-writing my list elements

Fairly new to python, very new to python classes. 对python来说是相当新的,对python类来说是非常新的。 Question is a bit involved. 问题涉及其中。 Most appreciative of your patience: 最感谢您的耐心:

I have a class "Star". 我有一堂课“明星”。 It is simple. 很简单。 Attributes x, v, and mass. 属性x,v和mass。 Another class, Galaxy, has an attribute "stars" which is just a list of star objects: 另一个类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 also has an attribute function called time_stepper. Galaxy还具有称为time_stepper的属性函数。 Suffice it to say time_stepper just updates all the elements of "stars" and then returns "stars": 只需说一下time_stepper即可更新“星标”的所有元素,然后返回“星标”即可:

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

Now, I'm trying to drive this thing and store the various updates of "stars" in a list called "history": 现在,我正在尝试驱动此事情并将“星星”的各种更新存储在称为“历史记录”的列表中:

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

Finally, my question: In each iteration of this loop, the new element of "stars" is added to "history", but ... and here it is ... all the previous elements of history are over-written and given the same values as the newest element of history! 最后,我的问题是:在此循环的每次迭代中,都会将新的“星星”元素添加到“历史记录”中,但是...在这里,... 历史记录的所有先前元素都被覆盖并赋予与历史的最新元素具有相同的价值! So what is going on? 那么发生了什么? I've run into things about python lists that I didn't understand before, but I thought I finally had it nailed down. 我遇到了以前不了解的有关python列表的问题,但我认为我终于确定了它。 Apparently not. 显然不是。 Thanks for your help. 谢谢你的帮助。

Addendum: Thanks to everyone for your help. 附录:感谢大家的帮助。 Didn't expect that many helpful replies and especially so soon. 没想到会有很多有用的答复,尤其是这么快。 My problem was that I was assuming these two pieces of code were essentially the same. 我的问题是我假设这两段代码本质上是相同的。 First: 第一:

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

Second: 第二:

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

And whoops! 哎呀! They aren't. 他们不是。 So in code 1, I guess, b is "re-pointed" to a completely new memory location while a[0] continues to point the the old b. 因此,在代码1中,我想b被“重新指向”到一个全新的存储位置,而a [0]继续指向旧的b。 In the second, the memory at b is "edited" and a[0] is still pointing to that location. 在第二个中,b处的内存被“编辑”,而a [0]仍指向该位置。 After the append, a[1] is also pointing to that location. 追加之后,a [1]也指向该位置。 Do I have it now? 我现在有吗?

I'm very new to python and am still figuring out the "pythonic" philosophy. 我对python还是很陌生,但仍在弄清楚“ pythonic”的哲学。 But to me, having a reassignment of pointers done straightforwardly, but a "deep copy" done in a more complicated way is sort of backwards from the way I usually want to do things. 但是对我来说,直接完成指针的重新分配,但是以更复杂的方式完成“深层复制”,这比我通常想要做的事情有些倒退。 Can anyone enlighten me? 谁能启发我? Thanks again. 再次感谢。

I think it is worth noting that if you have more than 1 galaxy, they'll share the same stars. 我认为值得注意的是,如果您拥有多个星系,它们将共享相同的恒星。 This could lead you to believe that you're overwriting your stars when you really aren't... 这可能会使您相信,当您并非如此时,您会覆盖您的星星。

I'm guessing you would probably be better with an __init__ that looks like: 我猜想使用__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]))

Here I've shifted the class attribute stars to be an instance attribute . 在这里,我将class属性 stars转换为instance属性 Now each instance will have it's own stars list instead of sharing one stars list with all of the other galaxies in the universe. 现在,每个实例将拥有自己的stars列表,而不是与宇宙中所有其他星系共享一个stars列表。

As others have noted, your history list is going to suffer from a similar problem (You have multiple references to the same list ). 正如其他人指出的那样,您的history列表将遇到类似的问题(您对同一列表有多个引用)。 However, the fix really depends on what you do in self.velstep and self.xstep . 但是,此修复程序实际上取决于您在self.velstepself.xstep If you modify the Star objects in place, then a simple (shallow) list copy won't do you any good (eg gal.time_stepper(0.1)[:] ). 如果在适当位置修改Star对象,那么简单的(浅)列表副本将gal.time_stepper(0.1)[:]例如gal.time_stepper(0.1)[:] )。 (You'll create a new list, but it will hold the same stars which are constantly being updated). (您将创建一个新列表,但它将包含不断更新的相同星星)。 In that case, you'll want copy.deepcopy when you append to your history list: 在这种情况下,当您追加到历史记录列表时,将需要copy.deepcopy

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

This is because the stars list is mutable - it is a changeable variable. 这是因为stars列表是可变的-它是一个可变变量。 When you call stars.append , it does not create a new list - it simple edits the existing list. 当您调用stars.append ,它不会创建新列表-而是简单地编辑现有列表。 And when you call history.append(x) , python does not create a fresh, clean copy of x - it assumes you want the "real" x to be placed in the history array. 当你骂history.append(x)蟒蛇不会创建一个新的,干净的副本x -它假定你想要的“真正的” x被放置在在history阵列。

If you'd like to copy the state of the list at each iteration, there are several options (see How to clone a list in python? ). 如果您想在每次迭代时复制列表的状态,则有几个选项(请参阅如何在python中克隆列表? )。

The copy module will do the trick. copy模块将解决问题。 It offers both 'shallow' and 'deep' copies - roughly speaking, deep copies attempt to also copy any other variables they find inside an object (for example, lists containing other lists), while shallow ones just go one layer down: 它提供了“浅”副本和“深”副本-大致来说,深副本还会尝试复制它们在对象中找到的任何其他变量(例如,包含其他列表的列表),而浅副本只是向下一层:

Here's shallow copies with copy : 这是带有copy的浅表副本:

import copy

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

And deep copies: 和深拷贝:

import copy

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

Slicing the array will work, since it always shallow copies as an intermediate step: 切片数组将起作用,因为它总是将浅表副本作为中间步骤:

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

You can also call list on the existing list - this typecast-esque operation always returns a new list object (again, shallowly): 您还可以在现有list上调用list -此类型转换式操作始终返回一个新的列表对象(再次,浅表):

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

It is not changing or over writing all of the values, but rather all of the elements in the history point to the same array object. 它并没有更改或覆盖所有值,而是历史记录中的所有元素都指向同一数组对象。 You need to assign by value as opposed to reference by using a copy of the array. 您需要使用数组的副本按值分配引用,而不是引用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM