使用eval(str()代替deepcopy()来深度复制列表是不是一种糟糕的做法



我想知道是否有理由使用deepcopy而不是这样:
list1 = [[1,2],[3,4],[5,6]]
list2 = eval(str(list1))
如果有其他很酷的方法,我很想知道。

使用eval要慢得多,因为它需要解析字符串并对其进行解释,而deepcopy不需要此步骤,而且您还需要预先转换为字符串,而deepcopy也不需要此转换。

这是我的机器上的两个结果:

>>> timeit.timeit('copy.deepcopy(ls)', setup='import copynls = [[1,2], [3,4]]')
3.9644698999999974
>>> timeit.timeit('eval(str(ls))', setup='ls = [[1,2], [3,4]]')
8.982202999999998

如果您刚刚获得(非复杂(list of lists,则通过列表理解复制似乎比eval:更快、更安全

import timeit
import json
import ujson
import copy

def _eval(l):
return eval(str(l))

def _copy(l):
return copy.deepcopy(l)

def _json(l):
return json.loads(json.dumps(l))

def _ujson(l):
return ujson.loads(ujson.dumps(l))

def _comp(l):
return [x[:] for x in l]

shortList = [[1, 2], [3, 4], [5, 6]]
longList = [[x, x + 1] for x in range(0, 50000)]
for lst in (shortList, longList):
for func in ("_eval", "_copy", "_json", "_ujson", "_comp"):
t1 = timeit.Timer(f"{func}({lst})", f"from __main__ import {func}")
print(f"{func} ran:", t1.timeit(number=1000), "milliseconds")

退出(短名单(:

_eval ran: 0.009196660481393337 milliseconds
_copy ran: 0.005948461592197418 milliseconds
_json ran: 0.004726926796138287 milliseconds
_ujson ran: 0.0011531058698892593 milliseconds
_comp ran: 0.00045751314610242844 milliseconds

输出(长列表(:

_eval ran: 16.720303252339363 milliseconds
_copy ran: 7.898970659822226 milliseconds
_json ran: 2.1138144126161933 milliseconds
_ujson ran: 1.2348785381764174 milliseconds
_comp ran: 0.5541304731741548 milliseconds

除了性能之外,还有很多很好的理由使用eval。关于一般的缺点,请看这里。

特别是关于你的例子,我想强调一个例子,事情出了严重的问题。想象一下,有一个类Foo,它存储任意值x:

class Foo:
def __init__(self, x):
self.x = x

def __repr__(self):
return f'{self.__class__.__name__}'

现在成像,您可以创建此类对象的列表,例如:

foos = [Foo(i) for i in range(5)]

如果您现在使用eval,试图创建列表的副本,结果将不会被请求到原始列表:

test = eval(str(foos))

您最终得到的不是Foo对象的列表,而是class types:的列表

foos = [Foo(i) for i in range(5)]
print(foos)
# [Foo, Foo, Foo, Foo, Foo]
print(foos[0].x)
# 0
test = eval(str(foos))
print(test)
# [<class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>, <class '__main__.Foo'>]
print(test[0].x)
# AttributeError: type object 'Foo' has no attribute 'x'

相关内容

  • 没有找到相关文章

最新更新