У меня есть довольно длинное уравнение, которое мне нужно интегрировать, используя scipy.integrate.quad, и мне было интересно, есть ли способ добавить лямбда-функции друг к другу. Я имею в виду что-то вроде этого

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

Уравнения, которые я действительно использую, намного сложнее, чем я намекаю здесь, поэтому для удобства чтения было бы полезно разбить уравнение на более мелкие, более управляемые части.

Есть ли способ сделать с лямбда-функциями? Или, возможно, другой способ, который даже не требует лямбда-функций, но даст тот же результат?

18
coffeepls 14 Дек 2015 в 10:03

5 ответов

Лучший ответ

В Python вы обычно будете использовать лямбду только для очень коротких, простых функций, которые легко помещаются в строку, которая их создает. (Некоторые языки имеют другие мнения.)

Как намекнул @DSM в своем комментарии, лямбды - это, по сути, ярлык для создания функций, когда не стоит давать им имя.

Если вы делаете более сложные вещи или если вам нужно дать коду имя для дальнейшей ссылки, лямбда-выражение не будет для вас чем-то вроде ярлыка - вместо этого вы можете def и простая старая функция.

Таким образом, вместо присвоения лямбда-выражения переменной:

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

Функции и лямбды являются «вызываемыми», что означает, что они, по сути, взаимозаменяемы, что касается 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 списку до одного значения).

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

18
RJHunter 14 Дек 2015 в 09:12

С 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])
10
eph 14 Дек 2015 в 07:47

Используйте приведенный ниже код, чтобы получить тот же результат, написав как можно меньше кода :

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)
4
Andriy Ivaneyko 7 Мар 2016 в 06:13

Для этого нет встроенных функций, но вы можете реализовать их довольно легко (конечно, с некоторой потерей производительности):

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

Другие операторы могут быть добавлены аналогичным образом.

11
fjarri 14 Дек 2015 в 07:11

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

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, вы можете комбинировать вывод двух функций, используя произвольные двоичные функции, без всяких ограничений. И большинства вещей в operator должно быть достаточно для типичных математических комбинаций, избегая необходимости писать лямбды.

Аналогичным образом вы можете определить lift1 и, возможно, lift3 тоже.

3
phipsgabler 14 Дек 2015 в 11:22