Is it a bad practice to use eval(str()) instead of deepcopy() to deepcopy a list of lists?

I’m wondering if there’s a reason to use deepcopy instead of this:
list1 = [[1,2],[3,4],[5,6]]
list2 = eval(str(list1))
If there’s another cool way of doing this I would love to know.

Answer

In case you just got (non-complex) list of lists copying via list comprehension seems to be fastest and more secure than 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")

Out (short list):

_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

Out (long list):

_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