Ответ 1
Я бы выбрал последнее, потому что компилятор Python не знает, имеет ли функция побочные эффекты, поэтому он вызывается для каждого элемента.
Какой из них лучше подходит для понимания списка в python (с точки зрения времени вычисления и циклов процессора). В примере (1) - значение f (r), оцениваемое на каждой итерации, или оно оценивается один раз и кэшируется?
y = [x*f(r) for x in xlist]
c = f(r)
y = [x*c for x in xlist]
где
def f(r):
... some arbitrary function ...
Я бы выбрал последнее, потому что компилятор Python не знает, имеет ли функция побочные эффекты, поэтому он вызывается для каждого элемента.
Он оценивает каждую итерацию. Посмотрите на это:
>>> def f():
... print("func")
...
>>> [f() for i in range(4)]
func
func
func
func
[None, None, None, None]
Как вы говорите, если f() не имеет побочных эффектов, сохранение возвращаемого значения переменной и использование этой переменной намного быстрее.
Вот простой способ узнать:
>>> def f():
... print "called"
... return 1
...
>>> [1+f() for x in xrange(5)]
called
called
called
called
called
[2, 2, 2, 2, 2]
так что да, если функция будет одинаковой каждый раз, тогда ее лучше вызвать ее за пределами понимания списка.
Функция f
будет вызываться для каждого элемента.
Для компилятора/интерпретатора очень сложно определить, что функция не должна вызываться много раз. Тогда очень вероятно, что функция называется много раз. Таким образом, использование второго решения всегда является лучшим решением.
Функции имеют нетривиальное время выполнения по сравнению с поиском имен, а кеширование значения считается приемлемым, если функция вызывается много раз, и каждый раз ожидается одно и то же значение.
Возможно, Python может делать это один или несколько раз, я не уверен, что буду полагаться на любое наблюдаемое поведение. Он может измениться в следующей версии.
Если вам важно убедиться, что функция вызывается только один раз, вызовите ее самостоятельно и сохраните результаты.