¿Cómo escribo una función que devuelve otra función?


93

En Python, me gustaría escribir una función make_cylinder_volume(r)que devuelva otra función. Esa función devuelta debe ser invocable con un parámetro hy devolver el volumen de un cilindro con altura hy radio r.

Sé cómo devolver valores de funciones en Python, pero ¿cómo devuelvo otra función ?


Respuestas:


191

Pruebe esto, usando Python:

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

Úselo así, por ejemplo con radius=10y height=5:

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

Tenga en cuenta que devolver una función fue una simple cuestión de definir una nueva función dentro de la función y devolverla al final, teniendo cuidado de pasar los parámetros apropiados para cada función. Para su información, la técnica de devolver una función de otra función se conoce como curado .


1
¿Entonces lo 10que pasaste está guardado en algún lugar? ¿Cuándo se recoge la basura?
sudo


19

Usando lambdas, también conocidas como funciones anónimas, puede abstraer la volumefunción dentro de la make_cylinder_volume_funcen una sola línea. De ninguna manera diferente a la respuesta de Óscar López, la solución con lambda sigue siendo en cierto sentido 'más funcional'.

Así es como puede escribir la respuesta aceptada usando una expresión lambda:

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

Y luego llame como lo haría con cualquier otra función curry:

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

Me doy cuenta de que está respondiendo a lo que se solicitó, pero por el bien de mi comprensión, si lambda h:se eliminara, ¿la función funcionaría igual?
Schoon

2
@schoon No, no funcionará en este caso. Este es en realidad un caso muy interesante para resaltar la idea de 'alcance variable' y currización de funciones (que básicamente se basa en el alcance variable). La razón por la que no funciona (en mi ejemplo) es porque returnintentará evaluar el resultado antes de regresar, y debido a que es un montón de variables, devolverá algún valor flotante (intente devolver una función y funcionará). lambdale dice que el siguiente código no debe evaluarse y también que el alcance de la variable r se conservará en las funciones devueltas por make_cylinder...
DaveIdito

10

Solo quiero señalar que puedes hacer esto 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)Hace exactamente lo mismo
R3ctor

1

Sé que llego demasiado tarde a la fiesta, pero creo que esta solución puede resultarle interesante.

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

Aquí hay documentación sobre cómo partialfunciona.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.