Wie schreibe ich eine Funktion, die eine andere Funktion zurückgibt?

87

In Python möchte ich eine Funktion schreiben, die eine make_cylinder_volume(r)andere Funktion zurückgibt. Diese zurückgegebene Funktion sollte mit einem Parameter aufrufbar sein hund das Volumen eines Zylinders mit Höhe hund Radius zurückgeben r.

Ich weiß, wie man Werte von Funktionen in Python zurückgibt, aber wie kann ich eine andere Funktion zurückgeben ?

Julian Das
quelle

Antworten:

185

Versuchen Sie dies mit Python:

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

Verwenden Sie es so, zum Beispiel mit radius=10und height=5:

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

Beachten Sie, dass das Zurückgeben einer Funktion eine einfache Angelegenheit war, eine neue Funktion innerhalb der Funktion zu definieren und am Ende zurückzugeben. Achten Sie dabei darauf, die entsprechenden Parameter für jede Funktion zu übergeben. Zu Ihrer Information, die Technik, eine Funktion von einer anderen Funktion zurückzugeben, ist als Currying bekannt .

Óscar López
quelle
4
Vielen Dank für den Hinweis auf Curry. Ich wünschte nur, ich könnte zweimal upvoten.
HeatfanJohn
1
Also ist das, was 10Sie übergeben haben, irgendwo gespeichert? Wann wird Müll gesammelt?
sudo
4
@ Sudo werfen Sie einen Blick auf en.wikipedia.org/wiki/Closure_(computer_programming)
David Hernandez
16

Mit Lambdas, auch als anonyme Funktionen bezeichnet, können Sie die volumeFunktion innerhalb von make_cylinder_volume_funcin eine einzelne Zeile abstrahieren . In keiner Weise anders als die Antwort von Óscar López ist die Lösung mit Lambda in gewissem Sinne immer noch „funktionaler“.

So können Sie die akzeptierte Antwort mit einem Lambda-Ausdruck schreiben:

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

Und rufen Sie dann wie jede andere Curry-Funktion auf:

volume_radius_1 = make_cylinder_volume_fun(1)
volume_radius_1(1) 
=> 3.141592653589793
DaveIdito
quelle
Mir ist klar, dass Sie antworten, was angefordert wurde, aber nach meinem Verständnis lambda h:würde die Funktion genauso funktionieren , wenn sie entfernt würde?
Schoon
2
@schoon Nein, in diesem Fall funktioniert es nicht. Dies ist tatsächlich ein sehr interessanter Fall, um die Idee des "variablen Scoping" und des Funktionscurrying (das im Wesentlichen auf dem varibalen Scoping beruht) hervorzuheben. Der Grund, warum es (in meinem Beispiel) nicht funktioniert, ist, dass der returnversucht, das Ergebnis vor der Rückgabe auszuwerten, und weil es sich um eine Reihe von Variablen handelt, einen Float-Wert zurückgibt (versuchen Sie, eine Funktion zurückzugeben, und es funktioniert). lambdasagt, dass der folgende Code nicht ausgewertet werden sollte und dass der Gültigkeitsbereich der Variablen r in den von zurückgegebenen Funktionen erhalten bleibt make_cylinder...
DaveIdito
10

Ich möchte nur darauf hinweisen, dass Sie dies mit Pymonade tun können

 import pymonad 

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

 add5 = add(5)
 add5(4)
 9
Erotemisch
quelle
from functools import partial add5 = partial(add, 5)Tut genau das gleiche
R3ctor
0

Ich weiß, dass ich zu spät zur Party komme, aber ich denke, Sie finden diese Lösung vielleicht interessant.

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

Hier finden Sie eine Dokumentation zur Funktionsweise partial.

R3ctor
quelle