2015-02-13 3 views
0

Если у меня есть 2 или 3 из тех же вычислений, выполненных внутри генератора для каждого цикла, есть ли способ просто установить их как переменную?Задать переменные в понимании списка python

Быстрый пример будет выглядеть так:

#Normal 
[len(i) for i in list if len(i) > 1] 

#Set variable 
[x for i in list if x > 1; x = len(i)] 

Перед кем говорит len(i) будет так быстро разница будет незначительной, я имею в виду для других вычислений, используя Len только что сделал это легче читать. Также, если есть способ, как бы вы установили несколько переменных?

Извинения, если это было задано раньше, но я искал вокруг и ничего не нашел.

+1

Как я понимаю, OP в основном пытается уменьшить вызовы 'func' от 2 до 1 на каждой итерации в выражении' [func (x) для x в списке, если func (x)> что-то] '. Штраф за вычисление «func» может значительно различаться для каждого такого вызова «func». –

ответ

5

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

def foo(x):  # assume this function is expensive 
    return 2*x 

>>> [j for j in (foo(i) for i in range(6)) if j > 4] 
#    ^only called once per element 
[6, 8, 10] 

Используя аналогичные функции и переменные к вашему примеру, вы бы

[x for x in (len(i) for i in list) if x > 1] 
+0

Ahh спасибо, этот способ имеет большой смысл, конечно, хотя было бы еще лучше переместить '(foo (i) для i в диапазоне (6))' из него тоже? – Peter

+0

Вы не можете переместить это выражение, вот что вызывает 'len' на всех ваших' i' в вашем примере. Внешнее представление списка выводит результат 'len' для каждого элемента, а затем сравнивает его с вашими критериями. – CoryKramer

+0

Есть ли какая-нибудь польза в смешении понимания списка и генератора? (скажем, над «вложенными списками»/«вложенными генераторами») –

1

с использованием itertools.imap в python2 будет эффективным способом сделать то, что вам нужно, и, скорее всего, опережать выражение генератора:

[x for x in imap(len, lst) if x > 4] 
3

Большинство реализаций Python, как вы правильно поняли, не имеют общей оптимизации подвыражения, поэтому ваше первое выражение действительно вызовет len (x) дважды за итерацию. Итак, почему не просто два соображения:

a = [len(x) for x in list] 
b = [x for x in a if x > 1] 

Это делает два прохода, но только один вызов len Если функция была дорогой, это, вероятно, победа. Я должен был это время убедиться.

Вложенная версия Cyber ​​- это по сути то же самое.

+0

_ «В большинстве реализаций Python нет, как вы правильно догадались, имеют общую оптимизацию подвыражений» _ как Дело в том, что в этом конкретном случае, как минимум, в CPython 3.3.0 не выполняется обычная оптимизация подвыражений. Учитывая данные OP (извините за встроенный код): '>>> def l (i): ... глобальный a ... a + = 1 ... return len (i) ... >>> а = 0 >>> [л (я) для г в my_lst, если л (я)> 1] [2, 2, 3] >>> 'Как можно видеть, моя функция 'l' называется 7 раз для списка из 4 элементов. –

+0

Функция с побочными эффектами в любом случае не будет иметь права на общую оптимизацию подвыражения. –

+0

- это оптимизатор, способный различать функцию, имеющую побочный эффект, или нет, если они не принадлежат к одному модулю? –

Смежные вопросы