2015-12-14 28 views
17

我有一個相當長的方程,我需要使用scipy.integrate.quad進行整合,並且想知道是否有方法將lambda函數相互添加。我想到的是這樣的在Python中使用相同的運算符添加lambda函數

y = lambda u: u**(-2) + 8 
x = lambda u: numpy.exp(-u) 
f = y + x 
int = scipy.integrate.quad(f, 0, numpy.inf) 

,我真的很喜歡使用複雜得多,比我在這裏暗示的公式,所以可讀性這將是該公式分解成更小的實用,更可管理的部分。

有沒有辦法處理lambda函數?或者也許另一種甚至不需要lambda函數的方式,但會給出相同的輸出?

+3

我對'scipy.integrate.quad'不熟悉,但'f = lambda u:y(u)+ x(u)'是一種將兩個函數加在一起的方法。 –

+5

另外:如果你打算立即給你的函數一個名字,爲什麼你要使用'lambda'? – DSM

+0

老實說,我使用lambda,因爲我不知道任何其他選項與我非常有限的python經驗,這就是爲什麼我加了最後一部分的問題。 – coffeepls

回答

17

在Python中,你」通常只使用lambda表示非常簡短的函數,這些函數可以很容易地放入創建它們的行內。 (某些語言有其他意見。)

由於@ DSM在他們的評論中暗示,lambdas本質上是創建函數時的一種快捷方式,因爲它不值得給它們起個名字。

如果您正在做更復雜的事情,或者如果您需要爲代碼提供一個名稱供以後參考,那麼lambda表達式對您而言並不是什麼捷徑 - 相反,您可能還需要def ine一個普通的舊功能。的

因此,而不是分配lambda表達式給一個變量:

y = lambda u: u**(-2) + 8 

可以定義變量是一個函數:

def y(u): 
    return u**(-2) + 8 

,讓你的房間說明了一下,或者是更復雜,或者你需要做的任何事情:

def y(u): 
    """ 
    Bloopinate the input 

    u should be a positive integer for fastest results. 
    """ 
    offset = 8 
    bloop = u ** (-2) 
    return bloop + offset 

函數和lambdas都是「callabl e「,這意味着就scipy.integrate.quad()而言,它們實質上是可互換的。

要組合可調對象,可以使用多種不同的技巧。

def triple(x): 
    return x * 3 

def square(x): 
    return x * x 

def triple_square(x): 
    return triple(square(x)) 

def triple_plus_square(x): 
    return triple(x) + square(x) 

def triple_plus_square_with_explaining_variables(x): 
    tripled = triple(x) 
    squared = square(x) 
    return tripled + squared 

有更高級的選項,我只會考慮如果它使你的代碼更清晰(它可能不會)。例如,你可以把可調用的列表:

all_the_things_i_want_to_do = [triple, square] 

一旦他們在列表中,你可以使用基於列表的操作對他們的工作(包括將它們依次reduce列表中向下一個值)。

但是,如果你的代碼和大多數代碼一樣,那麼按名稱調用對方的常規函數​​將是最簡單的編寫和最容易閱讀的。

+2

這可能是OP的真正問題的解決方案。 – justhalf

+0

這是pythonic和可測試的。 Lambda應該顯然是正確的。如降低字符串或添加常量。對於大多數情況下的數字代碼,最好是提取函數。它也不會像上面看到的那樣鼓勵單個名稱變量。 – bearrito

11

有對於沒有內置功能,但你可以很容易地實現(有一些性能損失,當然)它:

import numpy 

class Lambda: 

    def __init__(self, func): 
     self._func = func 

    def __add__(self, other): 
     return Lambda(
      lambda *args, **kwds: self._func(*args, **kwds) + other._func(*args, **kwds)) 

    def __call__(self, *args, **kwds): 
     return self._func(*args, **kwds) 

y = Lambda(lambda u: u**(-2) + 8) 
x = Lambda(lambda u: numpy.exp(-u)) 

print((x + y)(1)) 

其他運營商可以以類似的方式來添加。下面

+0

這對創建一個完整的DSL很有用,但請注意,有很多複雜的小問題需要處理。你需要做一些非常徹底的邊緣案例測試才能順利進行。對於大多數應用程序來說,這可能是不值得的麻煩,這讓RJHunter的解決方案留下了難題。儘管如此,用於重寫操作符的Python方式的+1。 – jpmc26

4

使用代碼來豐富相同的結果與寫作爲更少的代碼地:

y = lambda u: u**(-2) + 8 
x = lambda u: numpy.exp(-u) 
f = lambda u, x=x, y=y: x(u) + y(u) 
int = scipy.integrate.quad(f, 0, numpy.inf) 
10

隨着sympy你可以做功能操作是這樣的:

>>> import numpy 
>>> from sympy.utilities.lambdify import lambdify, implemented_function 
>>> from sympy.abc import u 
>>> y = implemented_function('y', lambda u: u**(-2) + 8) 
>>> x = implemented_function('x', lambda u: numpy.exp(-u)) 
>>> f = lambdify(u, y(u) + x(u)) 
>>> f(numpy.array([1,2,3])) 
array([ 9.36787944, 8.13533528, 8.04978707]) 
3

作爲一個功能性的程序員,我建議推廣的解決方案,以一個applicative combinator

In [1]: def lift2(h, f, g): return lambda x: h(f(x), g(x)) 
In [2]: from operator import add 
In [3]: from math import exp 
In [4]: y = lambda u: u**(-2) + 8 
In [5]: x = lambda u: exp(-u) 
In [6]: f = lift2(add, y, x) 
In [7]: [f(u) for u in range(1,5)] 
Out[7]: [9.367879441171443, 8.385335283236612, 8.160898179478975, 8.080815638888733] 

使用lift2,你可以結合使用任意的二進制功能於一身的pointfree方式兩個函數的輸出。並且operator中的大部分內容對於典型的數學組合應該足夠了,從而避免必須編寫任何lambda表達式。

在一個類似的方法中,你可能想要定義lift1或者lift3

相關問題