Наскоро се сблъсках със следния казус:
Как най-ефективно да преобразувам списък от repr на двойки елементи в списък от двойки елементи (т.е. да eval-на всеки string в python-ски tuple). Пример:
["('text1', 'text2')", "('text3', 'text4')", ... "('textn', 'textm')"]
Ето и четирите начина, които тествах:
from time import time import re def time_it(n, func, data): start = time() out = map(func, data) print 'time for case %d:' % n, time()-start return out data = map(repr, zip(map(str, range(10**6)), map(str, range(10**6)))) out = [] # 1 - eval на всеки елемент out.append(time_it(1, eval, data)) # 2 - премахване на ненужните символи out.append(time_it(2, lambda x: x[2:-2].split('\', \''), data)) # 3 - match-ване на стойностите с регулярен израз за всеки елемент pattern = re.compile(r'''\('(\w+)', '(\w+)'\)''') out.append(time_it(3, lambda x: pattern.search(x).group(1, 2), data)) # 4 - match-ване на стойностите с регулярен израз върху всички елементи обединени в един string pattern = re.compile(r"'(\w+)'") start = time() res = pattern.findall(''.join(data)) out.append(zip(res[::2], res[1::2])) print 'time for case 4:', time()-start print 'are they all the same?', len(filter(lambda o: o != out[0], map(lambda x: map(tuple, x), out))) == 0
Ето и времената:
time for case 1: 15.3229999542 time for case 2: 2.14499998093 time for case 3: 1.76999998093 time for case 4: 1.20600008965 are they all the same? True
Познах им класацията по бързодействие още преди да ги напиша :).
Естествено, най-правилният начин е този, който първи идва в главата на човек – eval. За съжаление обаче, ще трябва доста да почакате! Дори и да се направите на хитри и да пробвате със следния код (който е още по-грозен от вариант номер 4)
eval(repr(data).replace('"', ''))
пак времето нужно за изпълнение е около 10 пъти повече от вариант номер 4.
Макар че четвъртият пример е най-ефективен, не го препоръчвам поради ред причини, но най-вече защото кодът не се ръководи по форматa на данните, а просто агрегира всичко, което е между кавички. За това пък третият вариант е доста близък по време до четвъртия и за разлика от него се ръководи по структурата на данните, не прави един огромен текстов низ и е доста по-кратък и разбираем. Вариант номер 2 го забравете, че съществува 😉
Та, в заключение – гледайте да използвате по-рядко eval и да балансирате добре между разбираемост и бързодействие.
P.S. Eval is Evil by default… so never use it for evaluating external code or else your program will execute someone else’s code 🙂