Почему функция «оценка», по-видимому, занимает так много времени в Python?

#python

#питон

Вопрос:

TL;DR почему eval функция Python работает медленно?

Привет. Я решал упражнение по кодированию и заметил, что eval функция вызывала тайм-ауты для некоторых тестовых случаев, и мне было интересно, почему это так, поскольку я не особенно помню, чтобы читал, что функция работает медленно.

Вот упражнение:

Вам дается список из n неотрицательных целых чисел и целевое целое число. Узнайте, сколько существует возможных способов добавить » » или » — » между указанными целыми числами, чтобы получить цель. Например, ввод [1, 1, 1, 1, 1] и 3 будет возвращен 5 , так как всего существует пять способов вставить или — для получения 3 : -1 1 1 1 1 , 1-1 1 1 1 , 1 1-1 1 1 , 1 1 1-1 1 , 1 1 1 1-1 .

Решение, которое я изначально придумал, использовалось eval следующим образом:

 from itertools import product from typing import List   def solution(numbers: List[int], target: int) -gt; int:  numbers = [str(x) for x in numbers]  length = len(numbers)  all_operations = list(map(''.join, product(' -', repeat=length)))   answer = 0  for operation in all_operations:  eval_string = ''.join([''.join(x) for x in zip(operation, numbers)])   if eval(eval_string) == target:  answer  = 1   return answer  

Второе решение, которое проходит все тестовые случаи, не использует eval и просто выполняет арифметику шаг за шагом:

 from itertools import product from typing import List   def solution(numbers: List[int], target: int) -gt; int:  numbers = [str(x) for x in numbers]    length = len(numbers)  all_signs = list(map(''.join, product(' -', repeat=length)))    answer = 0  for operation in all_signs:  value = 0   for op, number in zip(operation, numbers):  if op == ' ':  value  = int(number)  elif op == '-':  value -= int(number)    if value == target:  answer  = 1    return answer  

Комментарии:

1. eval должен анализировать и интерпретировать заданную строку. Делать это медленнее, чем не делать этого.

2. Вы сравниваете код, который уже скомпилирован (когда ваше приложение запущено), с кодом, который еще предстоит оценить во время выполнения — это сравнение яблок с бананами.

3. @MikeScotty Извините, но я не совсем понимаю; будет ли использование eval функции ссылаться на код, который должен быть оценен во время выполнения?

4. В eval функции чтения кода, преобразовать его в байт-код во время выполнения, каждый раз в цикле.. а скрипт Python преобразует весь код в байт-код, как только перед казнью (это не компиляция кстати), во всяком случае, преобразование в байт-код-это ресурс, интенсивной эксплуатации, поэтому обычно это делается один раз до запуска кода.

Ответ №1:

Преобразование ваших значений в строки, а затем запуск eval не будет эффективным. Это будет быстрее, хотя, возможно, удастся улучшить это еще больше:

 import itertools  INTS = [1, 1, 1, 1, 1] CONST = 3 # build a new list comprised of the original INTS plus their negative values P = list(map(lambda x: -x, INTS))   INTS # work out the unique permutations s = set(itertools.permutations(P, len(INTS))) # iterate over (map) each unique permutations to see if its sum matches CONST print(list(map(lambda x: sum(x) == CONST, s)).count(True))