2016-07-09 6 views
3

Меня интересовало, когда я должен использовать генератор в функции, и когда мне нужно просто использовать список, поэтому я сделал несколько тестов с фильтрами и списками.Почему создание списка из объекта генератора занимает так много времени?

>>> timeit.timeit('list(filter(lambda x: x%10, range(10)))') 
3.281250655069016 
>>> timeit.timeit('[i for i in range(10) if i%10 != 0]') 
2.6070076799951494 
>>> timeit.timeit('filter(lambda x: x%10, range(10))') 
0.7457015149993822 

Затем я попытался с диапазоном (100):

>>> timeit.timeit('list(filter(lambda x: x%10, range(100)))') 
27.73180518404115 
>>> timeit.timeit('[i for i in range(100) if i%10 != 0]') 
18.659852175973356 
>>> timeit.timeit('filter(lambda x: x%10, range(100))') 
0.7294546449556947 

Почему это занимает так много больше, чтобы сделать список из объекта генератора, чем это делает, чтобы просто создать список? Если мне нужно было получить доступ к этому списку более одного раза, мне просто лучше было бы использовать понимание списка, а не создавать список из объекта-генератора?

+0

@PadraicCunningham хорошо, не все ли они получают 'next', называемые несколько раз? Но да, чем больше вы это называете, тем больше времени требуется для завершения итерации в последовательности. –

+0

@ Dandré, '[i для i в диапазоне (10), если i% 10! = 0]', где следующий вызов по отношению к самому списку? –

+0

@PadraicCunningham range() - это генератор, который имеет неявный вызов 'next' –

ответ

-1

Начну с ответа на ваш последний вопрос: да, вы должны использовать исчерпывающий список, а не list + filter, так как он более pythonic и, как вы показали, более эффективен.

Что касается того, почему он более эффективен, у вас есть служебный вызов функции (lambda) в коде filter, который у вас нет в списке понятий.

Вот еще один тест timeit, чтобы показать вам:

# First the sample with list & filter, for comparison base 
>>> timeit.timeit('list(filter(lambda x: x%10, range(10)))') 
10.984653161001916 
# Then the quickest comprehension list 
>>> timeit.timeit('[i for i in range(10) if i%10]') 
6.125996000002488 
# And an hybrid, comprehension list using a call to previously defined lambda 
>>> timeit.timeit('[i for i in range(10) if l(i)]', setup="l=lambda x: x%10") 
9.257114547002857 

Как вы можете видеть, большая часть разницы происходит от накладных расходов вызова функции.

за последние 1,7 необъяснимых секунд, вероятно, связано с filter тулбар в list в то время как список понимание строит значения непосредственно в список

3

Есть два разных вопроса, что видно из вопроса

  1. С minuscule данные синхронизации для автономного вызова фильтра очевидно, что вы используете Python 3.x, так как фильтр возвращает объект, похожий на генератор. Поэтому теоретически ничего не происходит.
  2. Первое выражение вызывает лямбда, вызов функции, который всегда стоит дорого в Python. Таким образом, понимание List превосходит фильтр, вызывающий лямбда, завернутый в список. [2]
Смежные вопросы