关于python:如何克隆或复制列表?

How to clone or copy a list?

在python中克隆或复制列表有哪些选项?

在使用new_list = my_list时,对new_list的任何修改每次都会更改my_list。为什么会这样?


使用new_list = my_list,实际上没有两个列表。任务只是复制了对列表的引用,而不是实际列表,因此new_listmy_list在任务完成后都引用了同一个列表。

要实际复制列表,您有多种可能:

  • 您可以使用内置的list.copy()方法(从python 3.3开始提供):

    1
    new_list = old_list.copy()
  • 您可以将其切片:

    1
    new_list = old_list[:]

    亚历克斯·马泰利(至少在2007年)对这一点的看法是,它是一种奇怪的语法,永远都没有意义。(他认为,下一个更易读)。

  • 您可以使用内置的list()功能:

    1
    new_list = list(old_list)
  • 您可以使用通用的copy.copy()

    1
    2
    import copy
    new_list = copy.copy(old_list)

    这比list()慢一点,因为它必须先找出old_list的数据类型。

  • 如果列表中包含对象,并且您也希望复制它们,请使用通用copy.deepcopy()

    1
    2
    import copy
    new_list = copy.deepcopy(old_list)

    显然是最慢和最需要记忆的方法,但有时不可避免。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import copy

class Foo(object):
    def __init__(self, val):
         self.val = val

    def __repr__(self):
        return str(self.val)

foo = Foo(1)

a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)

# edit orignal list and instance
a.append('baz')
foo.val = 5

print('original: %r
 list.copy(): %r
 slice: %r
 list(): %r
 copy: %r
 deepcopy: %r'

      % (a, b, c, d, e, f))

结果:

1
2
3
4
5
6
original: ['foo', 5, 'baz']
list.copy(): ['foo', 5]
slice: ['foo', 5]
list(): ['foo', 5]
copy: ['foo', 5]
deepcopy: ['foo', 1]


费利克斯已经给出了一个很好的答案,但我想我会对各种方法进行速度比较:

  • 10.59秒(105.9us/itn)-copy.deepcopy(old_list)
  • 10.16秒(101.6us/itn)-纯python Copy()方法用deepcopy复制类
  • 1.488秒(14.88us/itn)-纯python Copy()方法,不复制类(只复制dicts/lists/tuples)
  • 0.325秒(3.25us/itn)-for item in old_list: new_list.append(item)
  • 0.217秒(2.17us/itn)-[i for i in old_list](列表理解)
  • 0.186秒(1.86us/itn)-copy.copy(old_list)
  • 0.075秒(0.75us/itn)-list(old_list)
  • 0.053秒(0.53us/itn)-new_list = []; new_list.extend(old_list)
  • 0.039秒(0.39us/itn)-old_list[:](列表切片)
  • 所以最快的是列表切片。但是请注意,与copy.deepcopy()和python版本不同,copy.copy()list[:]list(list)不会复制列表中的任何列表、字典和类实例,因此如果原件更改,它们也会在复制列表中更改,反之亦然。

    (如果有人感兴趣或想提出任何问题,请看下面的脚本:)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    from copy import deepcopy

    class old_class:
        def __init__(self):
            self.blah = 'blah'

    class new_class(object):
        def __init__(self):
            self.blah = 'blah'

    dignore = {str: None, unicode: None, int: None, type(None): None}

    def Copy(obj, use_deepcopy=True):
        t = type(obj)

        if t in (list, tuple):
            if t == tuple:
                # Convert to a list if a tuple to
                # allow assigning to when copying
                is_tuple = True
                obj = list(obj)
            else:
                # Otherwise just do a quick slice copy
                obj = obj[:]
                is_tuple = False

            # Copy each item recursively
            for x in xrange(len(obj)):
                if type(obj[x]) in dignore:
                    continue
                obj[x] = Copy(obj[x], use_deepcopy)

            if is_tuple:
                # Convert back into a tuple again
                obj = tuple(obj)

        elif t == dict:
            # Use the fast shallow dict copy() method and copy any
            # values which aren't immutable (like lists, dicts etc)
            obj = obj.copy()
            for k in obj:
                if type(obj[k]) in dignore:
                    continue
                obj[k] = Copy(obj[k], use_deepcopy)

        elif t in dignore:
            # Numeric or string/unicode?
            # It's immutable, so ignore it!
            pass

        elif use_deepcopy:
            obj = deepcopy(obj)
        return obj

    if __name__ == '__main__':
        import copy
        from time import time

        num_times = 100000
        L = [None, 'blah', 1, 543.4532,
             ['foo'], ('bar',), {'blah': 'blah'},
             old_class(), new_class()]

        t = time()
        for i in xrange(num_times):
            Copy(L)
        print 'Custom Copy:', time()-t

        t = time()
        for i in xrange(num_times):
            Copy(L, use_deepcopy=False)
        print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t

        t = time()
        for i in xrange(num_times):
            copy.copy(L)
        print 'copy.copy:', time()-t

        t = time()
        for i in xrange(num_times):
            copy.deepcopy(L)
        print 'copy.deepcopy:', time()-t

        t = time()
        for i in xrange(num_times):
            L[:]
        print 'list slicing [:]:', time()-t

        t = time()
        for i in xrange(num_times):
            list(L)
        print 'list(L):', time()-t

        t = time()
        for i in xrange(num_times):
            [i for i in L]
        print 'list expression(L):', time()-t

        t = time()
        for i in xrange(num_times):
            a = []
            a.extend(L)
        print 'list extend:', time()-t

        t = time()
        for i in xrange(num_times):
            a = []
            for y in L:
                a.append(y)
        print 'list append:', time()-t

        t = time()
        for i in xrange(num_times):
            a = []
            a.extend(i for i in L)
        print 'generator expression extend:', time()-t

    编辑:在基准测试中添加了新样式、旧样式的类和dict,使Python版本更快,并添加了更多的方法,包括列表表达式和extend()


    我听说python 3.3+添加了list.copy()方法,它应该和切片一样快:

    newlist = old_list.copy()


    What are the options to clone or copy a list in Python?

    在python 3中,可以使用以下方法进行浅拷贝:

    1
    a_copy = a_list.copy()

    在python 2和3中,您可以使用原始文件的完整部分获得一个浅拷贝:

    1
    a_copy = a_list[:]

    解释

    复制列表有两种语义方法。浅副本创建相同对象的新列表,深副本创建包含新等效对象的新列表。

    浅表副本

    浅副本只复制列表本身,它是对列表中对象的引用容器。如果包含它们自己的对象是可变的,并且其中一个被更改了,那么更改将反映在两个列表中。

    在python 2和3中有不同的方法可以做到这一点。python 2方法也可以在python 3中使用。

    Python 2

    在python 2中,制作列表的浅显副本的惯用方法是使用完整的原始部分:

    1
    a_copy = a_list[:]

    您也可以通过列表构造函数传递列表来完成相同的事情,

    1
    a_copy = list(a_list)

    但是使用构造函数效率较低:

    1
    2
    3
    4
    5
    6
    >>> timeit
    >>> l = range(20)
    >>> min(timeit.repeat(lambda: l[:]))
    0.30504298210144043
    >>> min(timeit.repeat(lambda: list(l)))
    0.40698814392089844

    Python 3

    在python 3中,list获取list.copy方法:

    1
    a_copy = a_list.copy()

    在Python 3.5中:

    1
    2
    3
    4
    5
    6
    7
    8
    >>> import timeit
    >>> l = list(range(20))
    >>> min(timeit.repeat(lambda: l[:]))
    0.38448613602668047
    >>> min(timeit.repeat(lambda: list(l)))
    0.6309100328944623
    >>> min(timeit.repeat(lambda: l.copy()))
    0.38122922903858125

    生成另一个指针不会生成副本

    Using new_list = my_list then modifies new_list every time my_list changes. Why is this?

    my_list只是一个指向内存中实际列表的名称。当你说new_list = my_list你没有复制时,你只是添加了另一个名字,指向内存中的原始列表。当我们复制列表时,也会遇到类似的问题。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    >>> l = [[], [], []]
    >>> l_copy = l[:]
    >>> l_copy
    [[], [], []]
    >>> l_copy[0].append('foo')
    >>> l_copy
    [['foo'], [], []]
    >>> l
    [['foo'], [], []]

    列表只是指向内容的指针数组,所以一个浅拷贝只复制指针,所以您有两个不同的列表,但它们具有相同的内容。要复制内容,需要深度复制。

    深拷贝

    要在python 2或3中对列表进行深度复制,请在copy模块中使用deepcopy

    1
    2
    import copy
    a_deep_copy = copy.deepcopy(a_list)

    为了演示这如何允许我们创建新的子列表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> import copy
    >>> l
    [['foo'], [], []]
    >>> l_deep_copy = copy.deepcopy(l)
    >>> l_deep_copy[0].pop()
    'foo'
    >>> l_deep_copy
    [[], [], []]
    >>> l
    [['foo'], [], []]

    所以我们看到,深度复制的列表和原始列表完全不同。你可以滚动你自己的函数,但不能。你很可能会创建错误,否则使用标准库的deepcopy函数就不会有。

    不要使用eval

    您可能会看到这被用作deepcopy的一种方式,但不要这样做:

    1
    problematic_deep_copy = eval(repr(a_list))
  • 这很危险,尤其是当你从一个你不信任的来源来评估某件事的时候。
  • 如果您要复制的子元素没有可以通过eval复制等效元素的表示,那么这是不可靠的。
  • 它的性能也较差。
  • 在64位python 2.7中:

    1
    2
    3
    4
    5
    6
    7
    >>> import timeit
    >>> import copy
    >>> l = range(10)
    >>> min(timeit.repeat(lambda: copy.deepcopy(l)))
    27.55826997756958
    >>> min(timeit.repeat(lambda: eval(repr(l))))
    29.04534101486206

    在64位python 3.5上:

    1
    2
    3
    4
    5
    6
    7
    >>> import timeit
    >>> import copy
    >>> l = list(range(10))
    >>> min(timeit.repeat(lambda: copy.deepcopy(l)))
    16.84255409205798
    >>> min(timeit.repeat(lambda: eval(repr(l))))
    34.813894678023644


    已经有很多答案告诉你如何做一个正确的副本,但没有一个能说明你的原始"副本"失败的原因。

    python不在变量中存储值;它将名称绑定到对象。你最初的任务把my_list提到的对象也绑定到new_list上。无论您使用哪一个名称,仍然只有一个列表,因此当将其称为my_list时所做的更改将在将其称为new_list时持续。这个问题的其他每个答案都为您提供了创建绑定到new_list的新对象的不同方法。

    列表中的每个元素都像一个名称,因为每个元素都以非独占方式绑定到一个对象。一个浅拷贝创建一个新的列表,其中的元素与以前绑定到相同的对象。

    1
    2
    3
    new_list = list(my_list)  # or my_list[:], but I prefer this syntax
    # is simply a shorter way of:
    new_list = [element for element in my_list]

    若要进一步复制列表,请复制列表引用的每个对象,并将这些元素副本绑定到新列表。

    1
    2
    3
    import copy  
    # each element must have __copy__ defined for this...
    new_list = [copy.copy(element) for element in my_list]

    这还不是一个深度复制,因为列表中的每个元素都可能引用其他对象,就像列表绑定到其元素一样。要递归地复制列表中的每个元素,然后复制每个元素引用的每个其他对象,依此类推:执行深度复制。

    1
    2
    3
    import copy
    # each element must have __deepcopy__ defined for this...
    new_list = copy.deepcopy(my_list)

    请参阅文档以了解有关复制中的角盒的更多信息。


    new_list = list(old_list)


    使用thing[:]

    1
    2
    3
    4
    5
    6
    7
    8
    >>> a = [1,2]
    >>> b = a[:]
    >>> a += [3]
    >>> a
    [1, 2, 3]
    >>> b
    [1, 2]
    >>>

    python的习惯用法是newList = oldList[:]


    与其他具有变量和值的语言不同,Python具有名称和对象。

    本声明:

    1
    a = [1,2,3]

    指给列表(对象)命名为a,以及:

    1
    b = a

    只是给同一个对象a起了一个新的名字b,所以每当你对a做一些事情时,对象就会改变,因此b也会改变。

    唯一能真正复制的方法是创建一个新的对象,就像其他答案已经说过的那样。

    你可以在这里看到更多关于这个的信息。


    所有其他贡献者都给出了很好的答案,当您有一个一维(水平)列表时,这些答案是有效的,但是到目前为止提到的方法中,当您使用多维嵌套列表(列表)时,只有copy.deepcopy()可以克隆/复制列表,而不是让它指向嵌套的list对象。虽然费利克斯·克林在他的回答中提到了这一点,但这个问题还有一点要解决,而且可能还有一个使用内置的解决方案,这可能是一个比deepcopy更快的替代方案。

    new_list = old_list[:]copy.copy(old_list)'和py3k old_list.copy()用于单级列表时,它们恢复指向嵌套在old_listnew_list中的list对象,而对其中一个list对象的更改则永久存在于另一个对象中。

    编辑:新信息曝光

    As was pointed out by both Aaron Hall and PM 2Ring using eval() is not only a bad idea, it is also much slower than copy.deepcopy().

    This means that for multidimensional lists, the only option is copy.deepcopy(). With that being said, it really isn't an option as the performance goes way south when you try to use it on a moderately sized multidimensional array. I tried to timeit using a 42x42 array, not unheard of or even that large for bioinformatics applications, and I gave up on waiting for a response and just started typing my edit to this post.

    It would seem that the only real option then is to initialize multiple lists and work on them independently. If anyone has any other suggestions, for how to handle multidimensional list copying, it would be appreciated.

    正如其他人所说,使用copy模块和copy.deepcopy用于多维列表时,存在可以的重大性能问题。尝试用另一种方法复制多维列表而不使用deepcopy(我在一个只允许整个算法运行5秒以获得学分的课程中研究了一个问题),我想出了一种方法,使用内置函数复制嵌套列表而不让它们指向t彼此或嵌套在其中的list对象。我在任务中使用了eval()repr(),将旧列表的副本复制到新列表中,而不创建到旧列表的链接。其形式如下:

    1
    new_list = eval(repr(old_list))

    基本上,它所做的是将old_list表示为字符串,然后像对字符串表示的对象一样对字符串进行计算。这样,就不会链接到原始的list对象。创建一个新的list对象,每个变量指向自己的独立对象。下面是一个使用二维嵌套列表的示例。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    old_list = [[0 for j in range(y)] for i in range(x)] # initialize (x,y) nested list

    # assign a copy of old_list to new list without them pointing to the same list object
    new_list = eval(repr(old_list))

    # make a change to new_list
    for j in range(y):
        for i in range(x):
        new_list[i][j] += 1

    然后,如果检查每个列表的内容,例如4乘3的列表,python将返回

    1
    2
    3
    4
    5
    6
    7
    >>> new_list

    [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

    >>> old_list

    [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

    虽然这可能不是规范或语法上正确的方法,但它似乎工作得很好。我还没有测试过性能,但我想eval()rep()的运行开销比deepcopy要少。< /打击>


    Let's start from the beginning and explorer it a little deep :

    所以假设您有两个列表:

    1
    2
    list_1=['01','98']
    list_2=[['01','98']]

    我们必须复制这两个列表,现在从第一个列表开始:

    首先,让我们尝试一下一般的复制方法:

    1
    copy=list_1

    现在,如果您认为复制复制了列表,那么您可能是错的,让我们检查一下:

    1
    The id() function shows us that both variables point to the same list object, i.e. they share this object.
    1
    2
    print(id(copy))
    print(id(list_1))

    输出:

    1
    2
    4329485320
    4329485320

    惊讶?好吧,让我们来探索一下:

    所以我们知道python不会在变量中存储任何东西,变量只是引用对象,对象存储值。这里的对象是list,但是我们用两个不同的变量名创建了对同一对象的两个引用。所以两个变量都指向同一个对象:

    所以当你做copy=list_1时,它实际上在做什么:

    enter image description here

    在图像列表中,"1"和"copy"是两个变量名,但两个变量(即list变量)的对象相同。

    因此,如果您试图修改复制的列表,那么它也将修改原始列表,因为该列表只有一个,无论您是从复制的列表还是从原始列表进行修改,您都将修改该列表:

    1
    2
    3
    4
    copy[0]="modify"

    print(copy)
    print(list_1)

    输出:

    1
    2
    ['modify', '98']
    ['modify', '98']

    所以它修改了原始列表:

    What is the solution then?

    Solution :

    现在,让我们转到复制列表的第二种方法:

    1
    copy_1=list_1[:]

    现在,这个方法修复了我们在第一期中面对的问题,让我们检查一下:

    1
    2
    3
    4
    5
    print(id(copy_1))
    print(id(list_1))

    4338792136
    4338791432

    所以我们可以看到我们的两个列表都有不同的ID,这意味着两个变量都指向不同的对象,所以这里实际发生的事情是:

    enter image description here

    现在,让我们尝试修改列表,看看我们是否仍然面临前面的问题:

    1
    2
    3
    4
    copy_1[0]="modify"

    print(list_1)
    print(copy_1)

    输出:

    1
    2
    ['01', '98']
    ['modify', '98']

    所以你可以看到它没有修改原始列表,它只修改了复制的列表,所以我们可以接受它。

    所以现在我想我们结束了?等等,我们也要复制第二个嵌套列表,让我们试试pythonic方法:

    1
    copy_2=list_2[:]

    所以列表2应该引用另一个对象,它是列表2的副本,让我们检查一下:

    1
    print(id((list_2)),id(copy_2))

    我们得到输出:

    1
    4330403592 4330403528

    现在我们可以假设两个列表都指向不同的对象,那么现在让我们尝试修改它,让我们看看它给出了我们想要的:

    所以当我们尝试:

    1
    2
    3
    copy_2[0][1]="modify"

    print(list_2,copy_2)

    它给我们输出:

    1
    [['01', 'modify']] [['01', 'modify']]

    现在,这有点让人困惑,我们使用了Python的方式,但我们仍然面临着同样的问题。

    让我们理解:

    所以当我们这样做:

    1
    copy_2=list_2[:]

    实际上,我们只复制外部列表,而不复制嵌套列表,因此嵌套列表对于这两个列表都是相同的对象,让我们检查一下:

    1
    2
    print(id(copy_2[0]))
    print(id(list_2[0]))

    输出:

    1
    2
    4329485832
    4329485832

    所以事实上,当我们这样做时,会发生以下情况:

    enter image description here

    它创建列表的副本,但仅外部列表副本,而不是嵌套列表副本,两个变量的嵌套列表相同,因此如果尝试修改嵌套列表,则它也将修改原始列表,因为两个嵌套列表的嵌套列表对象相同。

    那么解决方案是什么呢?

    解决方案是deep copy

    1
    2
    from copy import deepcopy
    deep=deepcopy(list_2)

    现在让我们检查一下:

    1
    print(id((list_2)),id(deep))

    输出:

    1
    4322146056 4322148040

    这两个ID都不同,现在让我们检查嵌套列表ID:

    1
    2
    print(id(deep[0]))
    print(id(list_2[0]))

    输出:

    1
    2
    4322145992
    4322145800

    如您所见,两个ID都是不同的,所以我们可以假设两个嵌套列表现在都指向不同的对象。

    所以当你这样做时,实际发生的事情是:

    enter image description here

    所以这两个嵌套列表都指向不同的对象,并且它们现在具有嵌套列表的单独副本。

    现在,让我们尝试修改嵌套列表,看看它是否解决了前一个问题:

    所以如果我们这样做:

    1
    2
    deep[0][1]="modify"
    print(list_2,deep)

    输出:

    1
    [['01', '98']] [['01', 'modify']]

    所以你可以看到它没有修改原来的嵌套列表,只是修改了复制的列表。

    如果你喜欢我的详细答案,请通过投票让我知道,如果你对这个答案有任何疑问,请评论:)


    python 3.6.0计时

    下面是使用python 3.6.0的计时结果。记住这些时间是相对的,不是绝对的。

    我坚持只做简单的复制,还添加了一些在python2中不可能的新方法,例如list.copy()(python3切片等效)和list unpacking(*new_list, = list):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    METHOD                  TIME TAKEN
    b = a[:]                6.468942025996512   #Python2 winner
    b = a.copy()            6.986593422974693   #Python3"slice equivalent"
    b = []; b.extend(a)     7.309216841997113
    b = a[0:len(a)]         10.916740721993847
    *b, = a                 11.046738261007704
    b = list(a)             11.761539687984623
    b = [i for i in a]      24.66165203397395
    b = copy.copy(a)        30.853400873980718
    b = []
    for item in a:
      b.append(item)        48.19176080400939

    我们可以看到,考虑到python3 list.copy()方法可读性的提高,老的赢家仍然排在首位,但实际上并不是数量巨大。

    请注意,这些方法不会为除列表之外的任何输入输出等效的结果。它们都适用于可切片的对象,有一些适用于任何iterable,但只有copy.copy()适用于任何python对象。

    以下是相关方的测试代码(模板来自此处):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import timeit

    COUNT = 50000000
    print("Array duplicating. Tests run", COUNT,"times")
    setup = 'a = [0,1,2,3,4,5,6,7,8,9]; import copy'

    print("b = list(a)\t\t", timeit.timeit(stmt='b = list(a)', setup=setup, number=COUNT))
    print("b = copy.copy(a)\t\t", timeit.timeit(stmt='b = copy.copy(a)', setup=setup, number=COUNT))
    print("b = a.copy()\t\t", timeit.timeit(stmt='b = a.copy()', setup=setup, number=COUNT))
    print("b = a[:]\t\t", timeit.timeit(stmt='b = a[:]', setup=setup, number=COUNT))
    print("b = a[0:len(a)]\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
    print("*b, = a\t", timeit.timeit(stmt='*b, = a', setup=setup, number=COUNT))
    print("b = []; b.extend(a)\t", timeit.timeit(stmt='b = []; b.extend(a)', setup=setup, number=COUNT))
    print("b = []
    for item in a: b.append(item)\t"
    , timeit.timeit(stmt='b = []
    for item in a:  b.append(item)'
    , setup=setup, number=COUNT))
    print("b = [i for i in a]\t", timeit.timeit(stmt='b = [i for i in a]', setup=setup, number=COUNT))


    让我吃惊的是,这还没有被提到,所以为了完整性…

    您可以使用"splat operator"执行列表解包:*,它还将复制列表中的元素。

    1
    2
    3
    4
    5
    6
    7
    old_list = [1, 2, 3]

    new_list = [*old_list]

    new_list.append(4)
    old_list == [1, 2, 3]
    new_list == [1, 2, 3, 4]

    这种方法明显的缺点是它只在Python3.5+中可用。

    不过,从时间上看,这似乎比其他常用方法表现得更好。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    x = [random.random() for _ in range(1000)]

    %timeit a = list(x)
    %timeit a = x.copy()
    %timeit a = x[:]

    %timeit a = [*x]

    #: 2.47 μs ± 38.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    #: 2.47 μs ± 54.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
    #: 2.39 μs ± 58.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

    #: 2.22 μs ± 43.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)


    不确定这是否仍然是事实,但字典也有同样的行为。看看这个例子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    a = {'par' : [1,21,3], 'sar' : [5,6,8]}
    b = a
    c = a.copy()
    a['har'] = [1,2,3]

    a
    Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

    b
    Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}

    c
    Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}


    请注意,有些情况下,如果您已经定义了自己的自定义类,并且希望保留这些属性,那么应该使用copy.copy()copy.deepcopy()而不是其他选项,例如在python 3中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import copy

    class MyList(list):
        pass

    lst = MyList([1,2,3])

    lst.name = 'custom list'

    d = {
    'original': lst,
    'slicecopy' : lst[:],
    'lstcopy' : lst.copy(),
    'copycopy': copy.copy(lst),
    'deepcopy': copy.deepcopy(lst)
    }


    for k,v in d.items():
        print('lst: {}'.format(k), end=', ')
        try:
            name = v.name
        except AttributeError:
            name = 'NA'
        print('name: {}'.format(name))

    输出:

    1
    2
    3
    4
    5
    lst: original, name: custom list
    lst: slicecopy, name: NA
    lst: lstcopy, name: NA
    lst: copycopy, name: custom list
    lst: deepcopy, name: custom list

    在已经给出的答案中缺少了一种独立于Python版本的非常简单的方法,大多数时候您都可以使用它(至少我会这样做):

    1
    new_list = my_list * 1       #Solution 1 when you are not using nested lists

    但是,如果我的_列表包含其他容器(例如嵌套列表),您必须使用deepcopy,就像上面副本库中答案中建议的那样。例如:

    1
    2
    import copy
    new_list = copy.deepcopy(my_list)   #Solution 2 when you are using nested lists

    .bonus:如果您不想复制元素,请使用(又称浅复制):

    1
    new_list = my_list[:]

    让我们了解解决方案1和解决方案2之间的区别

    1
    2
    3
    4
    5
    6
    7
    >>> a = range(5)
    >>> b = a*1
    >>> a,b
    ([0, 1, 2, 3, 4], [0, 1, 2, 3, 4])
    >>> a[2] = 55
    >>> a,b
    ([0, 1, 55, 3, 4], [0, 1, 2, 3, 4])

    正如您所看到的,当我们不使用嵌套列表时,解决方案1工作得很好。让我们检查一下将解决方案1应用到嵌套列表时会发生什么。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    >>> from copy import deepcopy
    >>> a = [range(i,i+4) for i in range(3)]
    >>> a
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
    >>> b = a*1
    >>> c = deepcopy(a)
    >>> for i in (a, b, c): print i  
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]
    >>> a[2].append('99')
    >>> for i in (a, b, c): print i  
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5, 99]]   #Solution#1 didn't work in nested list
    [[0, 1, 2, 3], [1, 2, 3, 4], [2, 3, 4, 5]]       #Solution #2 - DeepCopy worked in nested list

    您可以在list()函数中使用bulit:

    1
    newlist=list(oldlist)

    我想这个密码对你有帮助。


    1
    new_list = my_list[:]

    new_list = my_list试着理解这一点。假设我的_列表在x位置的堆内存中,也就是说,我的_列表指向x。现在通过分配new_list = my_list,您可以让新的_列表指向x。这被称为浅拷贝。

    现在,如果您分配new_list = my_list[:],您只需将我的列表中的每个对象复制到新的列表中。这就是所谓的深度复制。

    另一种方法是:

    • new_list = list(old_list)
    • import copy
      new_list = copy.deepcopy(old_list)

    您可以使用内置的list.copy()方法(python 3.3+):https://docs.python.org/3/library/copy.html网站new_list=旧_list.copy()。


    您将使用python标准库中的deepcopy。

    在Python中,复制数据类型时,原始数据类型和复制的数据类型共享相同的内存位置。因此,对对象副本所做的任何更改都会反映在原始对象中。例如,考虑一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    my_lst=[1,2,3,4,5] #Python list
    print my_lst, ' my_lst (before copy)'

    my_lst_copy = my_lst=[1,2,3,4,5] #Simple copy of python list
    my_lst_copy[2] = 55 #Copy of python list changed

    print my_lst_copy, ' my_lst_copy (copy of python list)'
    print my_lst, ' my_lst (after copy)'

    >>>[1, 2, 3, 4, 5]  my_lst (before copy)
    >>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
    >>>[1, 2, 55, 4, 5]  my_lst (after copy)

    正如您之前注意到的,正如您在上述示例中再次注意到的,复制列表my_list_cp的任何元素的更改都会更改原始列表my_list。原因是没有新的分配给my_list_cp

    您可以使用python标准库中的deepcopy来抵消上述问题。在深度复制中,对象的副本复制到其他对象中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from copy import deepcopy

    my_lst=[1,2,3,4,5] #Python list
    print my_lst, ' my_lst (before copy)'

    my_lst_copy = deepcopy(my_lst) #Python list copied
    my_lst_copy[2] = 55 #Copy of python list changed

    print my_lst_copy, ' my_lst_copy (copy of python list)'
    print my_lst, ' my_lst (after copy)'

    >>>[1, 2, 3, 4, 5]  my_lst (before copy)
    >>>[1, 2, 55, 4, 5]  my_lst_copy (copy of python list)
    >>>[1, 2, 3, 4, 5]  my_lst (after copy)

    在上面的示例中,您看到复制后my_lst没有更改。