Bagaimana cara menulis fungsi yang mengembalikan fungsi lain?

93

Di Python, saya ingin menulis fungsi make_cylinder_volume(r)yang mengembalikan fungsi lain. Fungsi yang dikembalikan itu harus dapat dipanggil dengan parameter h, dan mengembalikan volume silinder dengan tinggi hdan radius r.

Saya tahu cara mengembalikan nilai dari fungsi dengan Python, tetapi bagaimana cara mengembalikan fungsi lain ?

Julian Das
sumber

Jawaban:

191

Coba ini, menggunakan Python:

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

Gunakan seperti ini, misalnya dengan radius=10dan height=5:

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

Perhatikan bahwa mengembalikan fungsi adalah masalah sederhana dalam mendefinisikan fungsi baru di dalam fungsi, dan mengembalikannya di akhir - berhati-hatilah untuk meneruskan parameter yang sesuai untuk setiap fungsi. FYI, teknik mengembalikan suatu fungsi dari fungsi lain disebut kari .

Óscar López
sumber
1
Jadi yang 10Anda berikan disimpan di suatu tempat? Kapan sampah dikumpulkan?
sudo
4
@sudo lihat di en.wikipedia.org/wiki/Closure_(computer_programming)
David Hernandez
19

Menggunakan lambda, juga dikenal sebagai fungsi anonim, Anda bisa mengabstraksi volumefungsi di dalam make_cylinder_volume_funcmenjadi satu baris. Tidak berbeda dengan jawaban Óscar López, solusi menggunakan lambda masih dalam arti 'lebih fungsional'.

Beginilah cara Anda menulis jawaban yang diterima menggunakan ekspresi lambda:

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

Dan kemudian panggil fungsi kari lainnya seperti yang Anda lakukan:

volume_radius_1 = make_cylinder_volume_fun(1)
volume_radius_1(1) 
=> 3.141592653589793
DaveIdito
sumber
Saya menyadari Anda menjawab apa yang diminta, tetapi demi pemahaman saya, jika lambda h:dihapus apakah fungsinya akan sama?
sekun
2
@schoon Tidak itu tidak akan berhasil dalam kasus ini. Ini sebenarnya kasus yang sangat menarik untuk menyoroti gagasan 'pelingkupan variabel' dan kari fungsi (yang pada dasarnya bergantung pada pelingkupan varibale). Alasan mengapa tidak berhasil (dalam contoh saya) adalah karena returnakan mencoba mengevaluasi hasil sebelum kembali, dan karena ini adalah sekumpulan variabel, itu akan mengembalikan beberapa nilai float (coba kembalikan fungsi dan itu akan berfungsi). lambdatelll bahwa kode berikut tidak boleh dievaluasi dan juga bahwa cakupan variabel r akan dipertahankan dalam fungsi yang dikembalikan oleh make_cylinder...
DaveIdito
10

Hanya ingin menunjukkan bahwa Anda dapat melakukan ini dengan pymonad

 import pymonad 

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

 add5 = add(5)
 add5(4)
 9
Erotemik
sumber
1
from functools import partial add5 = partial(add, 5)Apakah persis sama
R3ctor
1

Saya tahu saya terlambat ke pesta, tetapi menurut saya solusi ini mungkin menarik bagi Anda.

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

Berikut dokumentasi tentang cara partialkerjanya.

R3ctor
sumber