Почему вы оптимизируете это? Вы написали работающий, протестированный код, затем проверили свой алгоритм , профилированный ваш код и обнаружили, что оптимизация этого даст эффект? Вы делаете это в глубоком внутреннем цикле, где вы обнаружили, что проводите свое время? Если нет, не беспокойтесь.
Вы узнаете, какой из них работает быстрее всего по времени. Чтобы рассчитать это полезным способом, вам нужно будет специализировать его для фактического использования. Например, вы можете получить заметные различия в производительности между вызовом функции в понимании списка и встроенным выражением; неясно, действительно ли вы хотели получить первое или уменьшили его до того, чтобы сделать ваши дела похожими.
Вы говорите, что это не имеет значения, в конечном итоге вы получаете массив numpy или list
, но если вы выполняете такую микрооптимизацию, это имеет значение , так как они будут работать по-другому, когда вы будете использовать их позже. Поместить это может быть сложно, так что, надеюсь, окажется, что вся проблема спорна как преждевременная.
Обычно лучше просто использовать правильный инструмент для работы для ясности, читаемости и так далее. Редко мне было бы трудно выбирать между этими вещами.
- Если бы мне понадобились массивы numpy, я бы использовал их. Я бы использовал их для хранения больших однородных массивов или многомерных данных. Я часто их использую, но редко, где, я думаю, я хотел бы использовать список.
- Если бы я использовал их, я приложил бы все усилия, чтобы написать свои функции уже векторизованными, поэтому мне не пришлось использовать
numpy.vectorize
. Например, times_five
ниже может использоваться для массива numpy без декорации.
- Если у меня не было причины использовать numpy, то есть, если я не решал числовые математические задачи, не использовал специальные функции numpy, не сохранял многомерные массивы или что-то еще ...
- Если бы у меня уже была уже существующая функция , я бы использовал
map
. Вот для чего это.
- Если бы у меня была операция, которая помещалась в маленькое выражение, и мне не нужна была функция, я бы использовал понимание списка.
- Если бы я просто хотел выполнить операцию для всех случаев, но на самом деле не нуждался в сохранении результата, я использовал бы цикл for.
- Во многих случаях я бы фактически использовал
map
и перечислял ленивые эквиваленты пониманий: itertools.imap
и выражения генератора. Это может уменьшить использование памяти в n
случаях в некоторых случаях и может иногда избегать выполнения ненужных операций.
Если выясняется, что именно здесь кроются проблемы с производительностью, правильно подобного рода вещи сложно. очень очень часто люди выбирают не тот игрушечный футляр для решения своих реальных проблем. Хуже всего то, что крайне простые люди делают глупые общие правила, основанные на этом.
Рассмотрим следующие случаи (timeme.py опубликован ниже)
python -m timeit "from timeme import x, times_five; from numpy import vectorize" "vectorize(times_five)(x)"
1000 loops, best of 3: 924 usec per loop
python -m timeit "from timeme import x, times_five" "[times_five(item) for item in x]"
1000 loops, best of 3: 510 usec per loop
python -m timeit "from timeme import x, times_five" "map(times_five, x)"
1000 loops, best of 3: 484 usec per loop
Наивный наблюдатель пришел бы к выводу, что карта является наиболее эффективной из этих опций, но ответ по-прежнему "зависит". Подумайте о возможности использования преимуществ инструментов, которые вы используете: списки позволяют избежать определения простых функций; Numpy позволяет вам векторизовать вещи в C, если вы делаете правильные вещи.
python -m timeit "from timeme import x, times_five" "[item + item + item + item + item for item in x]"
1000 loops, best of 3: 285 usec per loop
python -m timeit "import numpy; x = numpy.arange(1000)" "x + x + x + x + x"
10000 loops, best of 3: 39.5 usec per loop
Но это еще не все, это еще не все. Рассмотрим силу изменения алгоритма. Это может быть еще более драматично.
python -m timeit "from timeme import x, times_five" "[5 * item for item in x]"
10000 loops, best of 3: 147 usec per loop
python -m timeit "import numpy; x = numpy.arange(1000)" "5 * x"
100000 loops, best of 3: 16.6 usec per loop
Иногда изменение алгоритма может быть даже более эффективным. Это будет становиться все более и более эффективным по мере увеличения чисел.
python -m timeit "from timeme import square, x" "map(square, x)"
10 loops, best of 3: 41.8 msec per loop
python -m timeit "from timeme import good_square, x" "map(good_square, x)"
1000 loops, best of 3: 370 usec per loop
И даже сейчас все это может иметь мало отношения к вашей реальной проблеме. Похоже, что numpy настолько хорош, если вы можете использовать его правильно, но у него есть свои ограничения: ни один из этих примеров не использовал реальные объекты Python в массивах. Это усложняет то, что должно быть сделано; очень даже А что, если нам удастся использовать типы данных C? Они менее надежны, чем объекты Python. Они не обнуляются. Переполнение целых чисел. Вы должны сделать дополнительную работу, чтобы получить их. Они статически напечатаны. Иногда эти вещи оказываются проблемами, даже неожиданными.
Итак, вы идете: окончательный ответ. «Это зависит».
# timeme.py
x = xrange(1000)
def times_five(a):
return a + a + a + a + a
def square(a):
if a == 0:
return 0
value = a
for i in xrange(a - 1):
value += a
return value
def good_square(a):
return a ** 2