Jak napisać funkcję, która zwraca inną funkcję?


93

W Pythonie chciałbym napisać funkcję, make_cylinder_volume(r)która zwraca inną funkcję. Ta zwrócona funkcja powinna być wywoływalna za pomocą parametru hi zwracać objętość walca wraz z wysokością hi promieniem r.

Wiem, jak zwrócić wartości z funkcji w Pythonie, ale jak zwrócić inną funkcję ?


Odpowiedzi:


191

Spróbuj tego, używając Pythona:

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

Użyj go w ten sposób, na przykład z radius=10i height=5:

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

Zwróć uwagę, że zwrócenie funkcji było prostą kwestią zdefiniowania nowej funkcji wewnątrz funkcji i zwrócenia jej na końcu - uważając, aby przekazać odpowiednie parametry dla każdej funkcji. FYI, technika zwracania funkcji z innej funkcji jest znana jako currying .


1
Więc 10przekazany przez Ciebie plik jest gdzieś przechowywany? Kiedy jest zbierany jako śmieci?
sudo


19

Używając wyrażeń lambd, zwanych również funkcjami anonimowymi, możesz wyodrębnić volumefunkcję wewnątrz elementu make_cylinder_volume_funcdo pojedynczego wiersza. W niczym nie różni się od odpowiedzi Óscara Lópeza, rozwiązanie wykorzystujące lambdę jest nadal w pewnym sensie „bardziej funkcjonalne”.

Oto jak możesz napisać zaakceptowaną odpowiedź za pomocą wyrażenia lambda:

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

A potem zadzwoń tak jak każdą inną funkcję curry:

volume_radius_1 = make_cylinder_volume_fun(1)
volume_radius_1(1) 
=> 3.141592653589793

Zdaję sobie sprawę, że odpowiadasz na to, o co prosiłem, ale dla mojego zrozumienia, czy gdyby lambda h:zostało usunięte, czy funkcja działałaby tak samo?
szkun

2
@schoon Nie, w tym przypadku nie zadziała. W rzeczywistości jest to bardzo interesujący przypadek, aby podkreślić ideę „zakresu zmiennego” i curry funkcji (która zasadniczo polega na określaniu zakresu zmiennego). Powodem, dla którego to nie działa (w moim przykładzie) jest to, że returnspróbuje ocenić wynik przed zwróceniem, a ponieważ jest to zbiór zmiennych, zwróci jakąś wartość zmiennoprzecinkową (spróbuj zwrócić funkcję i zadziała). lambdamówil, że poniższy kod nie powinien być oceniany, a także, że zakres zmiennej r zostanie zachowany w funkcjach zwracanych przez make_cylinder...
DaveIdito

10

Chcę tylko zaznaczyć, że możesz to zrobić za pomocą 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)Robi dokładnie to samo
R3ctor

1

Wiem, że jestem za późno na imprezę, ale myślę, że to rozwiązanie może Ci się spodobać.

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

Oto dokumentacja o tym, jak partialdziała.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.