Як написати функцію, яка повертає іншу функцію?


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

Зверніть увагу, що повернення функції було простою справою визначення нової функції всередині функції та повернення її в кінці - обережність передачі відповідних параметрів для кожної функції. FYI, техніка повернення функції з іншої функції відома як каррінг .


1
Отже, 10переданий вами десь зберігається? Коли збирається сміття?
sudo


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

Я розумію, що ви відповідаєте на запитуване, але для мого розуміння, якби 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працює.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.