Как мне написать функцию, которая возвращает другую функцию?

93

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

Я знаю, как возвращать значения из функций в Python, но как мне вернуть другую функцию ?

Джулиан Дас
источник

Ответы:

191

Попробуйте это, используя Python:

import math
def make_cylinder_volume_func(r):
    def volume(h):
        return math.pi * r * r * h
    return volume

Используйте его так, например, с radius=10и height=5:

volume_radius_10 = make_cylinder_volume_func(10)
volume_radius_10(5)
=> 1570.7963267948967

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

Оскар Лопес
источник
1
Значит 10, переданный вами код где-то хранится? Когда он собирается сборщиком мусора?
sudo
4
@sudo, взгляните на en.wikipedia.org/wiki/Closure_(computer_programming)
Дэвид Эрнандес,
19

Используя лямбды, также известные как анонимные функции, вы можете абстрагировать volumeфункцию внутри make_cylinder_volume_funcдо одной строки. Ничем не отличается от ответа Оскара Лопеса, решение с использованием лямбда по-прежнему в некотором смысле «более функционально».

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

import math
def make_cylinder_volume_fun(r):
    return lambda h: math.pi * r * r * h

А затем вызовите, как любую другую каррированную функцию:

volume_radius_1 = make_cylinder_volume_fun(1)
volume_radius_1(1) 
=> 3.141592653589793
DaveIdito
источник
Я понимаю, что вы отвечаете на то, что было запрошено, но, насколько я понимаю, в случае lambda h:удаления функция будет работать так же?
шхуна
2
@schoon Нет, в этом случае это не сработает. На самом деле это очень интересный случай, чтобы подчеркнуть идею «области видимости переменных» и каррирования функций (которые в основном полагаются на область видимости переменной). Причина, по которой это не работает (в моем примере), заключается в том, что returnон попытается оценить результат перед возвратом, и поскольку это набор переменных, он вернет некоторое значение с плавающей запятой (попробуйте вернуть функцию, и она будет работать). lambdaсообщает, что следующий код не должен оцениваться, а также что область видимости переменной r будет сохранена в функциях, возвращаемых функцией make_cylinder...
DaveIdito
10

Просто хочу отметить, что вы можете сделать это с помощью pymonad

 import pymonad 

 @pymonad.curry
 def add(a, b):
     return a + b

 add5 = add(5)
 add5(4)
 9
Эротемический
источник
1
from functools import partial add5 = partial(add, 5)Точно так же
R3ctor
1

Я знаю, что опаздываю на вечеринку, но думаю, это решение может вас заинтересовать.

from math import pi
from functools import partial

def cylinder_volume(r, h):
    return pi * r * r * h

make_cylinder_with_radius_2 = partial(cylinder_volume, 2)
make_cylinder_with_height_3 = partial(cylinder_volume, h=3)

print(cylinder_volume(2, 3))            # 37.6991118431
print(make_cylinder_with_radius_2(3))   # 37.6991118431
print(make_cylinder_with_height_3(2))   # 37.6991118431

Вот документация о том, как partialработает.

R3ctor
источник