在 python 中保持列表分开并避免浅拷贝
keeping lists separate and avoiding shallow copy in python
这是我的伪代码:
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 之间的区别。那不是我的问题。当我在 class instantiation/inheritance 中使用它时,我觉得有些事情搞砸了。我正在离线工作以生成我可以在此处提供的 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()
所以经过大量的调试我找到了这个错误的原因。一种可能的修复方法如下:
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 中有详细说明)
这是我的伪代码:
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 之间的区别。那不是我的问题。当我在 class instantiation/inheritance 中使用它时,我觉得有些事情搞砸了。我正在离线工作以生成我可以在此处提供的 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()
所以经过大量的调试我找到了这个错误的原因。一种可能的修复方法如下:
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 中有详细说明)