2015-12-14 16 views
17

Tôi có một phương trình khá dài mà tôi cần tích hợp qua việc sử dụng scipy.integrate.quad và tự hỏi liệu có cách nào để thêm hàm lambda vào nhau hay không. Những gì tôi có trong tâm trí là một cái gì đó như thế nàyThêm hàm lambda với cùng toán tử trong python

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

Các phương trình mà tôi đang thực sự sử dụng còn lâu mới phức tạp hơn tôi gợi ý ở đây, vì vậy để có thể đọc nó sẽ hữu ích để phá vỡ các phương trình thành nhỏ hơn, nhiều hơn các bộ phận có thể quản lý.

Có cách nào để thực hiện với chức năng lambda không? Hoặc có lẽ một cách khác mà thậm chí không yêu cầu hàm lambda nhưng sẽ cung cấp cho cùng một đầu ra?

+3

Tôi không quen với 'scipy.integrate.quad', nhưng' f = lambda u: y (u) + x (u) 'sẽ là một cách để thêm hai hàm này lại với nhau. –

+5

Ngoài ra: tại sao bạn lại sử dụng 'lambda' nếu bạn định đặt tên cho hàm của bạn ngay lập tức? – DSM

+0

Thành thật mà nói tôi đang sử dụng lambda bởi vì tôi không biết bất kỳ tùy chọn khác với kinh nghiệm python rất hạn chế của tôi, đó là lý do tại sao tôi thêm phần cuối cùng cho câu hỏi. – coffeepls

Trả lời

17

Trong Python, bạn' thường sẽ chỉ sử dụng một lambda cho các hàm rất đơn giản, ngắn gọn, dễ dàng khớp với bên trong dòng đang tạo ra chúng. (Một số ngôn ngữ có ý kiến ​​khác.)

Khi @DSM gợi ý trong nhận xét của họ, lambdas về cơ bản là lối tắt để tạo các hàm khi không đáng để đặt tên cho chúng.

Nếu bạn đang làm những điều phức tạp hơn, hoặc nếu bạn cần đặt tên cho mã sau này, biểu thức lambda sẽ không có nhiều phím tắt cho bạn - thay vào đó, bạn cũng có thể def ine một hàm cũ đơn giản.

Vì vậy, thay vì gán biểu thức lambda cho một biến:

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

Bạn có thể định nghĩa biến mà là một chức năng:

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

nào mang đến cho bạn phòng để giải thích một chút, hoặc là phức tạp hơn hoặc bất cứ điều gì bạn cần làm:

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

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

Chức năng và lambdas đều là "callabl e ", có nghĩa là chúng chủ yếu có thể hoán đổi cho đến tận scipy.integrate.quad().

Để kết hợp các cuộc gọi, bạn có thể sử dụng một số kỹ thuật khác nhau.

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 

Có nhiều tùy chọn nâng cao hơn mà tôi sẽ chỉ xem xét nếu nó làm cho mã của bạn rõ ràng hơn (có thể là không).Ví dụ, bạn có thể đặt callables trong một danh sách:

all_the_things_i_want_to_do = [triple, square] 

Một khi họ đang ở trong một danh sách, bạn có thể sử dụng hoạt động dựa trên danh sách để làm việc trên chúng (kể cả áp dụng chúng lần lượt để reduce danh sách xuống một giá trị duy nhất).

Nhưng nếu mã của bạn giống như hầu hết mã, các hàm thông thường chỉ gọi nhau theo tên sẽ là cách đơn giản nhất để viết và dễ đọc nhất.

+2

Đây có thể là giải pháp cho vấn đề thực sự của OP. – justhalf

+0

Đây là loại pythonic và testable. Lambda rõ ràng là đúng. Giống như hạ thấp chuỗi hoặc thêm một hằng số. Đối với mã số trong hầu hết các trường hợp, sẽ tốt hơn nếu trích xuất các hàm. Ngoài ra nó sẽ không khuyến khích biến tên duy nhất như chúng ta thấy ở trên. – bearrito

11

Không có tích hợp chức năng cho rằng, nhưng bạn có thể thực hiện nó khá dễ dàng (với một số hiệu suất hit, tất nhiên):

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)) 

nhà khai thác khác có thể được thêm vào trong một cách tương tự.

+0

Điều này có thể tốt cho việc tạo một DSL đầy đủ, nhưng lưu ý rằng có rất nhiều phức tạp để giải quyết. Bạn sẽ cần phải làm một số thử nghiệm trường hợp cạnh khá kỹ lưỡng để làm cho nó hoạt động trơn tru. Đối với hầu hết các ứng dụng, có lẽ không đáng để giải quyết rắc rối, điều này khiến bạn giải pháp của RJHunter. 1 cho cách Python của các toán tử ghi đè, mặc dù. – jpmc26

4

Sử dụng mã dưới đây để kết quả phong phú cùng với văn bản như mã ít hơn càng tốt:

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

Với sympy bạn có thể làm hoạt động chức năng như thế này:

>>> 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

Là một lập trình chức năng, tôi khuyên bạn nên khái quát hóa các giải pháp cho một 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] 

Sử dụng lift2, bạn có thể kết hợp đầu ra của hai chức năng sử dụng các hàm nhị phân tùy ý một cách pointfree. Và hầu hết các công cụ trong operator có lẽ là đủ cho các kết hợp toán học điển hình, tránh phải viết bất kỳ lambdas nào.

Trong một fasion tương tự, bạn có thể muốn xác định lift1 và có thể cả lift3.