在 "cloning" 对象时避免使用 clone = obj *1 是否有特殊原因?
Is there a particular reason that using clone = obj *1 is avoided when "cloning" objects?
在 this SO thread 中表明,就复制项目而言,切片比任何方法都快。
使用:
list1 = ['foo','bar']
copy1 = list1 * 1
list1.pop()
print 'list1: ' + list1
print 'copy1: ' + copy1
我得到:
list1: ['foo']
copy1: ['foo', 'bar']
有什么特别理由要避免制作这样的副本吗?
不要忘记您正在复制对 相同 对象的引用,这不是您(通常)期望的:
如果您要创建一个包含 3 个“1”列表的 list
:
>>> lst = [[1]] * 3
>>> lst
[[1], [1], [1]]
现在对第一项做点什么:
>>> lst[0].append(2)
糟糕,这三个位置都是同一个对象:
>>> lst
[[1, 2], [1, 2], [1, 2]]
我希望 [[1, 2], [1], [1]]
,但我想这是主观的,这就是我不会使用它的原因。至少不是可变对象。
就复制项目而言,切片比任何方法都快。
您可以自己轻松测试:
timeit.timeit('clone = lst * 1', 'lst = ["foo", "bar"]', number=10000000)
对我来说,我的时间是0.8731180049981049
用切片代替相同的测试:
timeit.timeit('clone = lst [:]', 'lst = ["foo", "bar"]', number=10000000)
给出时间:0.9454964299984567
所以 *
运算符似乎实际上更快。至于为什么人们使用 [:]
代替?它的作用更加明显。
这在复制列表的列表时出现故障,请考虑:
>>> lst = [[1], [2]]
使用切片和 *1
复制仍然允许修改原始列表
>>> copy1 = lst[:]
>>> copy1[0].append('x')
>>> lst # is affected by the above
[[1, 'x'], [2]]
>>> copy2 = lst * 1
>>> copy2[0].append('y')
>>> lst # is also affected by the above
[[1, 'x', 'y'], [2]]
但是通过列表推导可以深度复制序列
>>> copy3 = [l[:] for l in lst]
>>> copy3[0].append('z')
>>> lst # unaffected
[[1, 'x', 'y'], [2]]
>>> copy4 = [l * 1 for l in lst]
>>> copy4[0].append('z')
>>> lst # also unaffected
[[1, 'x', 'y'], [2]]
在 this SO thread 中表明,就复制项目而言,切片比任何方法都快。
使用:
list1 = ['foo','bar']
copy1 = list1 * 1
list1.pop()
print 'list1: ' + list1
print 'copy1: ' + copy1
我得到:
list1: ['foo']
copy1: ['foo', 'bar']
有什么特别理由要避免制作这样的副本吗?
不要忘记您正在复制对 相同 对象的引用,这不是您(通常)期望的:
如果您要创建一个包含 3 个“1”列表的 list
:
>>> lst = [[1]] * 3
>>> lst
[[1], [1], [1]]
现在对第一项做点什么:
>>> lst[0].append(2)
糟糕,这三个位置都是同一个对象:
>>> lst
[[1, 2], [1, 2], [1, 2]]
我希望 [[1, 2], [1], [1]]
,但我想这是主观的,这就是我不会使用它的原因。至少不是可变对象。
就复制项目而言,切片比任何方法都快。
您可以自己轻松测试:
timeit.timeit('clone = lst * 1', 'lst = ["foo", "bar"]', number=10000000)
对我来说,我的时间是0.8731180049981049
用切片代替相同的测试:
timeit.timeit('clone = lst [:]', 'lst = ["foo", "bar"]', number=10000000)
给出时间:0.9454964299984567
所以 *
运算符似乎实际上更快。至于为什么人们使用 [:]
代替?它的作用更加明显。
这在复制列表的列表时出现故障,请考虑:
>>> lst = [[1], [2]]
使用切片和 *1
复制仍然允许修改原始列表
>>> copy1 = lst[:]
>>> copy1[0].append('x')
>>> lst # is affected by the above
[[1, 'x'], [2]]
>>> copy2 = lst * 1
>>> copy2[0].append('y')
>>> lst # is also affected by the above
[[1, 'x', 'y'], [2]]
但是通过列表推导可以深度复制序列
>>> copy3 = [l[:] for l in lst]
>>> copy3[0].append('z')
>>> lst # unaffected
[[1, 'x', 'y'], [2]]
>>> copy4 = [l * 1 for l in lst]
>>> copy4[0].append('z')
>>> lst # also unaffected
[[1, 'x', 'y'], [2]]