Come scrivo una funzione che restituisce un'altra funzione?


93

In Python, mi piacerebbe scrivere una funzione make_cylinder_volume(r)che restituisca un'altra funzione. Quella funzione restituita dovrebbe essere richiamabile con un parametro he restituire il volume di un cilindro con altezza he raggio r.

So come restituire valori dalle funzioni in Python, ma come restituisco un'altra funzione ?


Risposte:


191

Prova questo, usando Python:

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

Usalo in questo modo, ad esempio con radius=10e height=5:

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

Si noti che la restituzione di una funzione consisteva semplicemente nel definire una nuova funzione all'interno della funzione e nella restituzione alla fine, facendo attenzione a passare i parametri appropriati per ciascuna funzione. Cordiali saluti, la tecnica per restituire una funzione da un'altra funzione è nota come currying .


1
Quindi quello che 10sei passato è conservato da qualche parte? Quando viene raccolta la spazzatura?
sudo


19

Usando lambda, note anche come funzioni anonime, puoi astrarre la volumefunzione all'interno make_cylinder_volume_funcdi una singola riga. Non diversamente dalla risposta di Óscar López, la soluzione che utilizza lambda è ancora in un certo senso "più funzionale".

Ecco come puoi scrivere la risposta accettata usando un'espressione lambda:

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

E poi chiama come faresti con qualsiasi altra funzione curry:

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

Mi rendo conto che stai rispondendo a ciò che è stato richiesto, ma per il bene della mia comprensione, se lambda h:fosse rimosso la funzione funzionerebbe allo stesso modo?
schoon

2
@schoon No, in questo caso non funzionerà. Questo è in realtà un caso molto interessante per evidenziare l'idea di "scoping variabile" e curry di funzioni (che fondamentalmente si basa sullo scoping varibale). Il motivo per cui non funziona (nel mio esempio) è perché returnproverà a valutare il risultato prima di restituire, e poiché è un mucchio di variabili, restituirà un valore float (prova a restituire una funzione e funzionerà). lambdadice che il codice seguente non dovrebbe essere valutato e anche che l'ambito della variabile r sarà preservato nelle funzioni restituite da make_cylinder...
DaveIdito

10

Voglio solo sottolineare che puoi farlo con 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)Fa esattamente lo stesso
R3ctor

1

So di essere in ritardo per la festa, ma penso che potresti trovare questa soluzione interessante.

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

Ecco la documentazione su come partialfunziona.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.