Функции высшего порядка против циклов - время работы и эффективность памяти? - PullRequest
8 голосов
/ 28 января 2012

Означает ли использование функций высшего порядка и лямбда-выражения время работы и эффективность памяти лучше или хуже? Например, чтобы умножить все числа в списке:

nums = [1,2,3,4,5]
prod = 1
for n in nums:
    prod*=n

против

prod2 = reduce(lambda x,y:x*y , nums)

Имеет ли версия HOF какое-либо преимущество перед версией цикла, кроме ее меньших строк кода / использует функциональный подход?

EDIT:

Я не могу добавить это как ответ, поскольку у меня нет необходимой репутации. Я привязан к профилированию цикла и HOF, используя timeit, как предложено @ DSM

def test1():         
    s= """
    nums = [a for a in range(1,1001)] 
    prod = 1 
    for n in nums:
        prod*=n
    """            
    t = timeit.Timer(stmt=s)
    return t.repeat(repeat=10,number=100)    

def test2():
    s="""
    nums = [a for a in range(1,1001)]     
    prod2 = reduce(lambda x,y:x*y , nums)
    """
    t = timeit.Timer(stmt=s)
    return t.repeat(repeat=10,number=100) 

И вот мой результат:

Loop:
[0.08340786340144211, 0.07211491653462579, 0.07162720686361926, 0.06593182661083438, 0.06399049758613146, 0.06605228229559557, 0.06419744588664211, 0.0671893658461038, 0.06477527090075941, 0.06418023793167627]
test1 average: 0.0644778902685
HOF:
[0.0759414223099324, 0.07616920129277016, 0.07570730355421262, 0.07604965128984942, 0.07547092059389193, 0.07544737286604364, 0.075532959799953, 0.0755039779810629, 0.07567424616704144, 0.07542563650187661]
test2 average: 0.0754917512762

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

Ответы [ 2 ]

7 голосов
/ 28 января 2012

Функции высшего порядка могут быть очень быстрыми.

Например, map(ord, somebigstring) на намного быстрее, чем эквивалентное понимание списка [ord(c) for c in somebigstring]. Бывший побеждает по трем причинам:

  • map () предварительно форматирует результирующую строку до длины somebigstring . Напротив, для понимания списка необходимо много вызовов realloc () по мере его роста.

  • map () должен выполнить только один поиск для ord , сначала проверив глобальные переменные, затем проверив и найдя их во встроенных программах. Понимание списка должно повторять эту работу на каждой итерации.

  • Внутренний цикл для карты работает на скорости C. Тело цикла для понимания списка представляет собой последовательность чистых шагов Python, каждый из которых должен отправляться или обрабатываться циклом eval.

Вот некоторые моменты времени, чтобы подтвердить прогноз:

>>> from timeit import Timer
>>> print min(Timer('map(ord, s)', 's="x"*10000').repeat(7, 1000))
0.808364152908
>>> print min(Timer('[ord(c) for c in s]', 's="x"*10000').repeat(7, 1000))
1.2946639061
1 голос
/ 28 января 2012

из моего опыта циклы могут делать вещи очень быстро, при условии, что они не вложены слишком глубоко, и со сложными более высокими математическими операциями для простых операций и одного уровня циклов это может быть так же быстро, как и любой другой способ, возможно, быстрее, до тех пор, пока в качестве индекса для цикла или циклов используются только целые числа, на самом деле это также будет зависеть от того, что вы делаете

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

...