列表理解中的浅或深复制

时间:2014-04-11 10:26:27

标签: python list python-2.7 list-comprehension

如果您在python中有一个列表(原始),如:

class CustomID (object):                   
    def __init__(self, *args):
        self.ID = ''
        self.manymore = float()
        self.visited = False
        self.isnoise = False
IDlist = ['1','2','3','4','5','6','7','8','9','10']
Original = list()
for IDs in IDlist:
    NewObject = CustomID()
    NewObject.ID = IDs
    Original.append(NewObject)

如果您对新列表和要在理解子列表中使用的函数有所了解:

def Func(InputList=list()):
    for objects in InputList:
        objects.visited = True
    return InputList
New_List = [member for member in Original if (int(member.ID)>5)]
ThirdList = Func(New_List)

此(New_List)是否会导致原始列表的浅或深副本?这个问题对我来说很重要,如果原始列表包含对象,哪些属性可以在代码中更改以遵循New_List创建(ThirdList)。 New_list被发送到一个函数,它将改变属性。问题是,如果您尝试将原始列表重用于具有不同理解的相同功能(假设(成员> 4)。

New_List = [member for member in Original if (int(member.ID)>4)]

实际上:

print New_List[3].visited

给出了真实。

2 个答案:

答案 0 :(得分:4)

您正在创建一个浅的过滤副本。

你的循环不会创建member的副本,它会直接引用它们。

不是您需要创建副本,原始列表中的所有对象都是不可变整数。此外,CPython实习小整数,创建副本只会导致完全相同的对象用于这些。

为了说明,请尝试创建包含可变对象的列表的副本。我在这里使用了一本字典:

>>> sample = [{'foo': 'bar'}]
>>> copy = [s for s in sample]
>>> copy[0]['spam'] = 'eggs'
>>> copy.append({'another': 'dictionary'})
>>> sample
[{'foo': 'bar', 'spam': 'eggs'}]

copy列表是一个新的列表对象,包含对sample中包含的同一字典的引用。更改该字典会反映在copysample中,但附加到copy不会改变原始列表。

对于更新后的循环代码,您的示例会生成一个仍然共享对象的New_List列表,而New_List[3].visited实际上是True

>>> New_List[3].ID
'8'
>>> New_List[3].visited
True

因为它仍然是Original索引7处的相同对象:

>>> New_List[3] is Original[7]
True

ThirdList索引2中仍然存在的对象相同:

>>> ThirdList[2] is New_List[3]
True

答案 1 :(得分:0)

另一个对我有用的想法是在类

中实现flagClear方法
class CustomID (object):                   
    def __init__(self, *args):
        self.ID = ''
        self.manymore = float()
        self.visited = False
        self.isnoise = False
    def flagClear(self):
        self.visited = False
        return self

然后,每次我构建一个新列表时,只需使用该方法:

New_List = [member.flagClear() for member in Original if (int(member.ID)>4)]

如果我在CustomID中修改的唯一内容是.visited标志,那么这可行。显然,它不会是完美的。如果有人需要一个完整的解决方案,Martijn Pieters的建议将最有效(实现.copy()方法):

import copy
class CustomID (object):                   
    def __init__(self, *args):
        self.ID = ''
        self.manymore = float()
        self.visited = False
        self.isnoise = False
    def CustomCopy(self):
        return copy.deepcopy(self)

New_List = [member.CustomCopy() for member in Original if (int(member.ID)>4)]

谢谢Martijn,这对我来说真是一次学习经历。