Python быстрый вопрос о пониманиях и списках - PullRequest
7 голосов
/ 14 февраля 2020

Просто хотел спросить, почему это (понимание списка, если я не ошибаюсь):

def s(number):
    return sum([n for n in range(number) if n%3==0 or n%5==0])
s(100)

в два раза быстрее (108 шагов при визуализации python), чем это (202 шага):

def s(number):
    return sum(n for n in range(number) if n%3==0 or n%5==0)
s(100)

?

А также, хотя первый код работает быстрее, второй код имеет какие-либо преимущества в каких-либо случаях? Может быть, использует меньше памяти? Я просто не знаю, о чем я говорю. Любые разъяснения будут с благодарностью.

1 Ответ

2 голосов
/ 15 февраля 2020

Производительность обоих ваших фрагментов довольно схожа, очевидно, не каждый шаг одинаков. Для небольших значений number первый код (список) немного быстрее, но для больших number второй код (генератор) выигрывает.

Другое дело - использование памяти - для создания списка требуется объем памяти, пропорциональный его размер, поэтому больший number потребляет больше оперативной памяти. Более того, по мере роста списка требуется перераспределение памяти, что в конечном итоге вызывает сборщик мусора (timeit() по умолчанию отключает gc, искажение результатов). С другой стороны, версия генератора использует одинаковый (минимальный) объем памяти для любого number.

Вывод состоит в том, что вы должны использовать выражения генератора всякий раз, когда это возможно. Это особенно важно, когда вы заботитесь об объеме памяти и / или работаете с большими числами. Кроме того, в этом случае ваш код будет немного короче и чище (спорный).

Этот вопрос объясняется в PEP 289 , представляющем выражения генератора.

...