Могу ли я удалить двойное вычисление при сохранении лямбда-выражения

#python #lambda #ternary-operator

#python #лямбда #тернарный оператор

Вопрос:

 def bar(x):
    # some expensive calculation
    <snip>

foo = lambda(x): bar(x) if bar(x) > 10 else 0
  

Однако здесь я дважды вычислил foo. Есть ли способ по-прежнему записывать это как однострочное, но избегать двойного вычисления. Я пытался

 foo = lambda(x): v if (v = bar(x)) > 10 else 0
  

но это не работает.

Комментарии:

1. Вы можете сохранить foo(x) в переменной tmp и использовать ее в своем коде.

Ответ №1:

Предварительная оценка:

 foo    = lambda(x): x if x > 10 else 0
result = foo(bar(x))
  

Здесь вы можете увидеть, в чем сходство с вашим кодом:

 lambda (x): foo(x) if foo(x) > 10 else 0 == (lambda(x): x if x > 10 else 0)(foo(x))
  

То, что вы ищете, невозможно, если вы не создадите какой-то объект с изменяемым состоянием или какой-то другой странный трюк.

ответ @Alakazam сложный и умный, используйте его на свой страх и риск. Может быть лучше использовать итераторы и next избегать дополнительного промежуточного списка:

 lambda x: next(res if res > 10 else 0 for res in (bar(x), ))
  

Здесь у вас есть живой пример

Ответ №2:

Да, вы можете избежать двойного вычисления в лямбда. Но это действительно некрасиво, и вам следует избегать этого. Вот как это выглядит:

 foo = lambda x: next(b if b > 10 else 0 for b in [bar(x)])
  

Легко ли это читать и понимать? Нет, абсолютно нет. Я не собираюсь это объяснять; посмотрим, сможете ли вы в этом разобраться. Это явно не очень хорошее решение, так что же вам следует сделать вместо этого? Вы должны использовать реальную функцию вместо лямбда.

 def foo(x):
    b = bar(x)
    return b if b > 10 else 0
  

Это намного проще для чтения и явно лучше.

Ответ №3:

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

foo = lambda x: [res if res>10 else 0 for res in [bar(x)]][0]

Комментарии:

1. я думаю, это лучше: lambda x: next(res if res > 10 else 0 for res in (bar(x), )) Причина в том, что вы избегаете промежуточного выделения памяти

2. @Netwave Я не думаю, что промежуточный malloc уместен, даже если это зависит от функции, вы не экономите много памяти.

Ответ №4:

С таким же успехом можно просто определить другую функцию:

 def bar(x):
    # some expensive calculation
    <snip>

def bar_threshold(x,t):
    y = bar(x)
    return y if y>t else 0

foo = lambda x: bar_threshold(x,10)
  

(или переопределите bar, если вы обнаружите, что используете его только с пороговым значением)

Ответ №5:

Я попытался создать декоратор / оболочку некоторой функции…

 def funcdec(func):
    def inner(x):
        if func(x) > 10:
           return func(x)
        else:
           return 0
  

затем

 @funcdec
def bar(x):
    return x * 2
  

затем я пытаюсь….:

 foo = lambda x: bar(x)
  

дайте мне результат :

 foo(2)
  

возвращает 0
и

 foo(10)
  

верните 20