保持列表分开并避免python中的浅拷贝

时间:2015-07-17 01:42:52

标签: python shallow-copy

这是我的伪代码:

class foo(bar):
    def __init__(self, aList):
        bar.__init__(self, aList)
        self.initialList = aList
    def clock(self):
        modify(self.workingList)
        if(something):
            self.workingList = self.initialList
        assert self.initialList == range(10)

class bar(object):
    def __init__(self, aList):
        self.workingList = aList

程序的正常操作如下:

a = range(10)
b = foo(a)
for i in xrange(10000):
    b.clock()

这不起作用因为我做了

self.workingList = self.initialList

self.workingList指向同一个对象而不是复制它。那么当我做的时候

modify(self.workingList)

它还修改了self.initialList,它意味着保持不变。

我的解决方法是替换

self.workingList = self.initialList

self.workingList = [i for i in self.initialList]

我甚至更换了

self.initialList = aList

使用:

self.initialList = [j for j in aList]

虽然我认为这应该在原则上有效,但它并没有在实践中解决问题。我通过assert语句验证了这一点。我似乎误解了一些pythonic语义。有人可以解释一下吗?

谢谢!

编辑: 请注意,我理解deepcopy和shallowcopy之间的区别。这不是我的问题所在。当我在类实例化/继承中使用它时,我觉得有些东西搞砸了。我正在离线工作以生成我可以在这里提供的MCV代码。请继续关注该更新。

更新:

我在MCVE中找到了C,这是错误:

class bar(object):
    def __init__(self, aList):
        self.workingList = aList

class foo(bar):
    def __init__(self, aList):
        bar.__init__(self, aList)
        self.initialList = list(aList)
    def clock(self):
        self.workingList[2] = max(self.workingList[3], 2)
        #print self.workingList
        if(1):
            self.workingList = list(self.initialList)
        try:
                assert self.initialList == range(10)
        except:
                print self.initialList
                print self.workingList
                assert self.initialList == range(10)


a = range(10)
for i in xrange(10):
        b = foo(a)
        for j in xrange(100000):
                b.clock()

1 个答案:

答案 0 :(得分:-1)

经过大量调试后我发现了这个bug的原因。一种可能的解决方法如下:

class bar(object):
    def __init__(self, aList):
        self.workingList = list(aList) #aList

原因是python按值传递对象引用。这是一个link,可以很好地解释它。

它与我的代码有关的方式是每次我在foo.clock()中更改self.workingList:

modify(self.workingList)

它实际上修改了aList指向的对象(在构造函数之外!!),所以当我创建一个新的foo实例(aList)时,我将一个新的错误版本的aList传递给它。这太棒了!

最棘手的事情是重新分配self.workingList不会创建这个错误(虽然它会传递引用),但修改self.workingList会,因为python按值传递对象引用(所有这些都被解释)详情请见link