Como faço para escrever uma função que retorna outra função?


97

Em Python, gostaria de escrever uma função make_cylinder_volume(r)que retorne outra função. Essa função retornada deve ser chamada com um parâmetro he retornar o volume de um cilindro com altura he raio r.

Eu sei como retornar valores de funções em Python, mas como faço para retornar outra função ?


Respostas:


194

Experimente isso, usando Python:

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

Use-o assim, por exemplo, com radius=10e height=5:

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

Observe que retornar uma função era uma simples questão de definir uma nova função dentro da função e retorná-la no final - tendo o cuidado de passar os parâmetros apropriados para cada função. FYI, a técnica de retornar uma função de outra função é conhecida como currying .


1
Então, o que 10você passou está armazenado em algum lugar? Quando é coletado o lixo?
sudo


20

Usando lambdas, também conhecidas como funções anônimas, você pode abstrair a volumefunção dentro de make_cylinder_volume_funcem uma única linha. Em nada diferente da resposta de Óscar López, a solução usando lambda ainda é em certo sentido 'mais funcional'.

É assim que você pode escrever a resposta aceita usando uma expressão lambda:

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

E então chame como você faria qualquer outra função curry:

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

Percebi que você está respondendo o que foi solicitado, mas pelo meu entendimento, se lambda h:fosse retirada a função funcionaria da mesma forma?
escola

2
@schoon Não, não funcionará neste caso. Este é realmente um caso muito interessante para destacar a ideia de 'escopo variável' e currying de função (que basicamente depende do escopo varibale). A razão pela qual não funciona (no meu exemplo) é porque o returntentará avaliar o resultado antes de retornar e, como é um monte de variáveis, retornará algum valor flutuante (tente retornar uma função e ela funcionará). lambdainforma que o código a seguir não deve ser avaliado e também que o escopo da variável r será preservado nas funções retornadas por make_cylinder...
DaveIdito

10

Só quero salientar que você pode fazer isso com 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)Faz exatamente o mesmo
R3ctor

1

Sei que estou muito atrasado para a festa, mas acho que você pode achar esta solução 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

Aqui está a documentação sobre como partialfunciona.


-1

Aqui está um grande exemplo que cobre muitos dos casos de argumentos múltiplos em uma função

def maths(var='NA'):
if var.lower() == 'add':
    def add(*args):
        return "Sum is : "+str(sum(args))
    return add
elif var.lower() == 'substract':
    def substract(a,b):
        if a>b:
            return "Difference is : "+str(a-b)
        else:
            return "Difference is : "+str(b-a)
    return substract
elif var.lower() == 'multiply':
    def multiply(*args):
        temp = 1
        for x in args:
            temp = temp*x
        return "multiplication is : "+str(temp)
    return multiply
elif var.lower() == 'divide':
    def divide(a,b):
        return "Division is : "+str(a/b)
    return divide
else:
    print("Please choose one of given operations: 'add','substract','multiply','divide'")

Aqui, primeiro chame a função matemática com a operação necessária e, em seguida, use a função retornada para o cálculo real

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.