如何克隆列表以使其在分配后不会意外更改?

问:

使用 new_list = my_list 时,对 new_list 的任何修改每次都会更改 my_list。为什么会这样,我如何克隆或复制列表以防止它?

答1:

一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会

new_list = my_list 实际上并没有创建第二个列表。赋值只是复制对列表的引用,而不是实际的列表,因此 new_list 和 my_list 在赋值后引用同一个列表。

要实际复制列表,您有几个选项:

您可以使用内置的 list.copy() 方法(自 Python 3.3 起可用):

new_list = old_list.copy()

你可以把它切片:

new_list = old_list[:]

Alex Martelli 对此的看法(至少 back in 2007)是,这是一种奇怪的语法,永远使用它没有意义。 😉(在他看来,下一个更具可读性)。

您可以使用内置的 list() 函数:

new_list = list(old_list)

您可以使用通用的 copy.copy():

import copy
new_list = copy.copy(old_list)

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

如果您还需要复制列表的元素,请使用通用 copy.deepcopy():

import copy
new_list = copy.deepcopy(old_list)

显然是最慢和最需要内存的方法,但有时是不可避免的。这是递归操作的;它将处理任意数量的嵌套列表(或其他容器)级别。

例子:

import copy

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

    def __repr__(self):
        return f'Foo({self.val!r})'

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(f'original: {a}\nlist.copy(): {b}\nslice: {c}\nlist(): {d}\ncopy: {e}\ndeepcopy: {f}')

结果:

original: ['foo', Foo(5), 'baz']
list.copy(): ['foo', Foo(5)]
slice: ['foo', Foo(5)]
list(): ['foo', Foo(5)]
copy: ['foo', Foo(5)]
deepcopy: ['foo', Foo(1)]

正如@Georgy 在下面的答案中正确指出的那样,对 new_list 值的任何更改也会更改 my_list 中的值。所以实际上 copy.deepcopy() 方法是唯一没有参考原始列表及其值的真实副本。

你是对的,它是由你编辑的,但由 @cryo 发布 抱歉混淆了!

哪个最快?

我对 json 列表有同样的问题(列表的每个元素都是一个 json),唯一有效的是 new_list = copy.deepcopy(old_list) ;我写这篇文章是因为任何人都可能遇到同样的问题。谢谢!

+1 切片 [:] 这是一种简单而紧凑的语法,每次需要复制列表时都使用它确实有意义,并且可以避免 deepcopy

答2:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

Felix 已经提供了一个很好的答案,但我想我会对各种方法进行速度比较:

10.59 秒 (105.9 µs/itn) - copy.deepcopy(old_list) 10.16 秒 (101.6 µs/itn) - 使用 deepcopy 复制类的纯 Python Copy() 方法 1.488 秒 (14.88 µs/itn) - 不是纯 Python Copy() 方法复制类(仅 dicts/lists/tuples)0.325 秒(3.25 µs/itn)-对于 old_list 中的项目:new_list.append(item) 0.217 秒(2.17 µs/itn)-[i for i in old_list](列表理解) 0.186 秒 (1.86 µs/itn) - copy.copy(old_list) 0.075 秒 (0.75 µs/itn) - list(old_list) 0.053 秒 (0.53 µs/itn) - new_list = []; new_list.extend(old_list) 0.039 sec (0.39 µs/itn) - old_list[:] (列表切片)

所以最快的是列表切片。但请注意,copy.copy()、list[:] 和 list(list) 与 copy.deepcopy() 和 python 版本不同,不会复制列表中的任何列表、字典和类实例,因此如果原件更改,它们将在也复制列表,反之亦然。

(如果有人感兴趣或想提出任何问题,这是脚本:)

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

这是否意味着追加和列表理解是最好的选择?

我有一个包含类列表的缓存,我想获取锁,复制列表,释放锁。我希望使用内置副本来保护复制出的列表在缓存副本更改时不被更改就足够了。

我继续回到这个答案,以确保我使用的是最有效的方法。测试这个最简单的方法是什么?或者是否有一个数据库具有所有最好的方法来最小化运行时间?

答3:

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

我有 been told 那个 Python 3.3+ adds the list.copy() 方法,它应该和切片一样快:

newlist = old_list.copy()

是的,根据文档 docs.python.org/3/library/stdtypes.html#mutable-sequence-types,s.copy() 创建了 s 的浅表副本(与 s[:] 相同)。

实际上,目前看来,python3.8、.copy() 比切片略快。请参阅下面的@AaronsHall 答案。

@loved.by.Jesus:是的,它们 added optimizations for Python level method calls in 3.7 已扩展为 C extension method calls in 3.8 by PEP 590,从而消除了每次调用方法时创建绑定方法的开销,因此调用 alist.copy() 的成本现在是 dict查找 list 类型,然后是一个相对便宜的无参数函数调用,最终调用与切片相同的东西。切片仍然需要构建一个 slice 对象,然后通过类型检查和解包来做同样的事情。

当然,他们正在研究 optimizing out the repeated builds of constant slices,因此在 3.10 中切片可能会再次获胜。不过,这一切都毫无意义;渐近性能是相同的,并且固定开销相对较小,因此您使用哪种方法并不重要。

答4:

打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!

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

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

a_copy = a_list.copy()

在 Python 2 和 3 中,您可以获得包含原始完整切片的浅拷贝:

a_copy = a_list[:]

解释

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

浅表副本

浅拷贝只复制列表本身,它是对列表中对象的引用的容器。如果自身包含的对象是可变的并且其中一个已更改,则更改将反映在两个列表中。

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

蟒蛇2

在 Python 2 中,制作列表浅表副本的惯用方法是使用原始列表的完整切片:

a_copy = a_list[:]

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

a_copy = list(a_list)

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

>>> timeit
>>> l = range(20)
>>> min(timeit.repeat(lambda: l[:]))
0.30504298210144043
>>> min(timeit.repeat(lambda: list(l)))
0.40698814392089844

蟒蛇 3

在 Python 3 中,列表获取 list.copy 方法:

a_copy = a_list.copy()

在 Python 3.5 中:

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

制作另一个指针不会复制

使用 new_list = my_list 然后在每次 my_list 更改时修改 new_list。为什么是这样?

my_list 只是一个指向内存中实际列表的名称。当您说 new_list = my_list 时,您不是在制作副本,您只是在添加另一个名称,该名称指向内存中的原始列表。当我们复制列表时,我们可能会遇到类似的问题。

>>> l = [[], [], []]
>>> l_copy = l[:]
>>> l_copy
[[], [], []]
>>> l_copy[0].append('foo')
>>> l_copy
[['foo'], [], []]
>>> l
[['foo'], [], []]

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

深拷贝

要制作 deep copy of a list, in Python 2 or 3, use deepcopy in the copy module:

import copy
a_deep_copy = copy.deepcopy(a_list)

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

>>> import copy
>>> l
[['foo'], [], []]
>>> l_deep_copy = copy.deepcopy(l)
>>> l_deep_copy[0].pop()
'foo'
>>> l_deep_copy
[[], [], []]
>>> l
[['foo'], [], []]

所以我们看到深度复制的列表与原始列表完全不同。您可以推出自己的功能 - 但不要。通过使用标准库的 deepcopy 函数,您可能会创建原本不会出现的错误。

不要使用评估

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

problematic_deep_copy = eval(repr(a_list))

这很危险,尤其是当您从不信任的来源评估某些东西时。这是不可靠的,如果您正在复制的子元素没有可以评估以重现等效元素的表示。它的性能也较低。

在 64 位 Python 2.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 上:

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

如果列表是 2D,则不需要 deepcopy。如果它是列表列表,并且这些列表中没有列表,则可以使用 for 循环。目前,我正在使用 list_copy=[] for item in list: list_copy.append(copy(item)),它要快得多。

答5:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

让我们从头开始,探讨这个问题。

因此,假设您有两个列表:

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

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

所以首先让我们尝试将变量 copy 设置为我们的原始列表 list_1:

copy = list_1

现在,如果您认为副本复制了 list_1,那么您就错了。 id 函数可以告诉我们两个变量是否可以指向同一个对象。让我们试试这个:

print(id(copy))
print(id(list_1))

输出是:

4329485320
4329485320

这两个变量是完全相同的参数。你惊喜吗?

正如我们所知,Python 不会在变量中存储任何内容,变量只是引用对象,而对象存储值。这里的对象是一个 list,但我们通过两个不同的变量名创建了对同一个对象的两个引用。这意味着两个变量都指向同一个对象,只是名称不同。

当您执行 copy = list_1 时,它实际上是在执行以下操作:

https://i.stack.imgur.com/vNGqw.jpg

在图像中 list_1 和 copy 是两个变量名,但两个变量的对象相同,即 list。

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

copy[0] = "modify"

print(copy)
print(list_1)

输出:

['modify', '98']
['modify', '98']

所以它修改了原始列表:

现在让我们转到用于复制列表的 Pythonic 方法。

copy_1 = list_1[:]

此方法解决了我们遇到的第一个问题:

print(id(copy_1))
print(id(list_1))

4338792136
4338791432

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

https://i.stack.imgur.com/iitLk.jpg

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

copy_1[0] = "modify"

print(list_1)
print(copy_1)

输出是:

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

如您所见,它只修改了复制的列表。这意味着它奏效了。

你认为我们完成了吗?不,让我们尝试复制我们的嵌套列表。

copy_2 = list_2[:]

list_2 应引用作为 list_2 副本的另一个对象。让我们检查:

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

我们得到输出:

4330403592 4330403528

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

copy_2[0][1] = "modify"

print(list_2, copy_2)

这给了我们输出:

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

这可能看起来有点令人困惑,因为我们之前使用的方法相同。让我们试着理解这一点。

当你这样做时:

copy_2 = list_2[:]

您只复制外部列表,而不是内部列表。我们可以再次使用 id 函数来检查这一点。

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

输出是:

4329485832
4329485832

当我们执行 copy_2 = list_2[:] 时,会发生这种情况:

https://i.stack.imgur.com/3hPti.jpg

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

解决办法是什么?解决方案是 deepcopy 函数。

from copy import deepcopy
deep = deepcopy(list_2)

让我们检查一下:

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

4322146056 4322148040

两个外部列表都有不同的 ID。让我们在内部嵌套列表上试试这个。

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

输出是:

4322145992
4322145800

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

这意味着当您执行 deep = deepcopy(list_2) 时实际发生的情况:

https://i.stack.imgur.com/O7yoo.jpg

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

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

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

它输出:

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

如您所见,它没有修改原始嵌套列表,它只修改了复制的列表。

答6:

huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。

已经有很多答案告诉您如何制作正确的副本,但没有一个回答您的原始“副本”失败的原因。

Python 不在变量中存储值;它将名称绑定到对象。您的原始作业将 my_list 引用的对象也绑定到 new_list。无论您使用哪个名称,仍然只有一个列表,因此在将其称为 my_list 时所做的更改将在将其称为 new_list 时保持不变。此问题的其他每个答案都为您提供了创建新对象以绑定到 new_list 的不同方法。

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

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]

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

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

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

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

有关复制中极端情况的更多信息,请参阅 the documentation。

答7:

huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。

使用thing[:]

>>> a = [1,2]
>>> b = a[:]
>>> a += [3]
>>> a
[1, 2, 3]
>>> b
[1, 2]
>>> 

答8:

huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。

Python 3.6 时序

以下是使用 Python 3.6.8 的计时结果。请记住,这些时间是相对的,而不是绝对的。

我坚持只做浅拷贝,还添加了一些在 Python 2 中无法实现的新方法,例如 list.copy()(Python 3 slice equivalent)和两种形式的 list unpacking(*new_list, = list 和new_list = [*list]):

METHOD                TIME TAKEN
b = [*a]               2.75180600000021
b = a * 1              3.50215399999990
b = a[:]               3.78278899999986  # Python 2 winner (see above)
b = a.copy()           4.20556500000020  # Python 3 "slice equivalent" (see above)
b = []; b.extend(a)    4.68069800000012
b = a[0:len(a)]        6.84498999999959
*b, = a                7.54031799999984
b = list(a)            7.75815899999997
b = [i for i in a]    18.4886440000000
b = copy.copy(a)      18.8254879999999
b = []
for item in a:
  b.append(item)      35.4729199999997

我们可以看到 Python 2 的赢家仍然表现出色,但并没有远远超过 Python 3 list.copy(),尤其是考虑到后者的卓越可读性。

黑马是解包和重新打包方法 (b = [*a]),它比原始切片快约 25%,比其他解包方法 (*b, = a) 快两倍以上。

b = a * 1 的表现也出奇的好。

请注意,这些方法不会为列表以外的任何输入输出等效结果。它们都适用于可切片对象,少数适用于任何可迭代对象,但只有 copy.copy() 有效对于更通用的 Python 对象。

以下是相关方 (Template from here) 的测试代码:

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", 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\t", timeit.timeit(stmt='b = a[0:len(a)]', setup=setup, number=COUNT))
print("*b, = a\t\t\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 = []\nfor 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))
print("b = [*a]\t\t", timeit.timeit(stmt='b = [*a]', setup=setup, number=COUNT))
print("b = a * 1\t\t", timeit.timeit(stmt='b = a * 1', setup=setup, number=COUNT))

与HuntsBot一起,探索全球自由职业机会–huntsbot.com

可以在 3.8 b=[*a] 上确认类似的故事 - 一种明显的方法;)。

在复制如此小的列表时,其中一些时间比较并不是特别有意义。使用一系列列表长度(包括一些非常大的长度)进行测试会提供更多信息。

计时数字应该四舍五入到适当的有效数字位数。 15 位有效数字没有任何意义。

我基本上只是在这里粘贴了时序代码的原始输出。似乎您的抱怨更多是关于 timeit 如何显示时间,我几乎无法控制。

a * 1 方法在 2.x 中真的不可能吗?

答9:

huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。

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

答10:

HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com

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

虽然 new_list = old_list[:]、copy.copy(old_list)’ 和 Py3k old_list.copy() 适用于单级列表,但它们恢复为指向嵌套在 old_list 和 new_list 中的 list 对象,并更改为 { 4} 对象在另一个对象中永久存在。

编辑:新信息曝光

正如 Aaron Hall 和 PM 2Ring 都指出的那样,使用 eval() 不仅是一个坏主意,而且比 copy.deepcopy() 慢得多。这意味着对于多维列表,唯一的选择是 copy.deepcopy()。话虽如此,当您尝试在中等大小的多维数组上使用它时,性能会下降,因此它确实不是一个选择。我尝试使用 42x42 数组进行计时,对于生物信息学应用程序来说,这不是闻所未闻的,甚至不是那么大,我放弃了等待回复,只是开始输入我对这篇文章的编辑。似乎唯一真正的选择是初始化多个列表并独立处理它们。如果有人对如何处理多维列表复制有任何其他建议,将不胜感激。

正如其他人所说,使用 copy 模块和copy.deepcopy 多维列表存在严重性能问题。

这并不总是有效,因为不能保证 repr() 返回的字符串足以重新创建对象。此外,eval() 是不得已的工具;有关详细信息,请参阅 SO 老手 Ned Batchelder 的Eval really is dangerous。因此,当您提倡使用 eval() 时,您真的应该提到它可能很危险。

有道理。尽管我认为 Batchelder 的观点是,在 Python 中使用 eval() 函数通常是一种风险。与其说你是否在代码中使用该函数,不如说它本身就是 Python 中的一个安全漏洞。我的示例没有将它与从 input()、sys.agrv 甚至文本文件接收输入的函数一起使用。它更像是初始化一个空白多维列表一次,然后只是有一种在循环中复制它的方法,而不是在循环的每次迭代中重新初始化。

正如@AaronHall 所指出的,使用 new_list = eval(repr(old_list)) 可能存在严重的性能问题,因此除了这是一个坏主意之外,它可能也太慢而无法工作。

答11:

huntsbot.com洞察每一个产品背后的需求与收益,从而捕获灵感

令我惊讶的是,这还没有被提及,所以为了完整起见…

您可以使用“splat 运算符”执行列表解包:*,它还将复制列表的元素。

old_list = [1, 2, 3]

new_list = [*old_list]

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

这种方法的明显缺点是它仅在 Python 3.5+ 中可用。

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

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)

修改副本时此方法的行为如何?

@not2qubit 你的意思是追加或编辑新列表的元素。在示例中 old_list 和 new_list 是两个不同的列表,编辑一个不会改变另一个(除非您直接改变元素本身(例如列表列表),这些方法都不是深拷贝)。

原文链接:https://www.huntsbot.com/qa/2Vb0/how-do-i-clone-a-list-so-that-it-doesnt-change-unexpectedly-after-assignment?lang=zh_CN&from=csdn

保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值