Làm cách nào để viết một hàm trả về một hàm khác?


93

Trong Python, tôi muốn viết một hàm make_cylinder_volume(r)trả về một hàm khác. Hàm trả về đó phải có thể gọi được với một tham số hvà trả về thể tích của hình trụ có chiều cao hvà bán kính r.

Tôi biết cách trả về giá trị từ các hàm trong Python, nhưng làm cách nào để trả về một hàm khác ?


Câu trả lời:


191

Hãy thử điều này, sử dụng Python:

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

Sử dụng nó như thế này, ví dụ với radius=10height=5:

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

Lưu ý rằng việc trả về một hàm là một vấn đề đơn giản của việc xác định một hàm mới bên trong hàm và trả lại nó sau cùng - hãy cẩn thận chuyển các tham số thích hợp cho mỗi hàm. FYI, kỹ thuật trả về một hàm từ một hàm khác được gọi là currying .


1
Vì vậy, 10bạn đã vượt qua được lưu trữ ở đâu đó? Khi nào nó được thu gom rác?
sudo


19

Sử dụng lambdas, còn được gọi là hàm ẩn danh, bạn có thể tóm tắt volumehàm bên trongmake_cylinder_volume_func thành một dòng duy nhất. Không khác gì câu trả lời của Óscar López, giải pháp sử dụng lambda vẫn có nghĩa là 'chức năng hơn'.

Đây là cách bạn có thể viết câu trả lời được chấp nhận bằng cách sử dụng biểu thức lambda:

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

Và sau đó gọi như bạn bất kỳ hàm cà ri nào khác:

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

Tôi nhận ra rằng bạn đang trả lời những gì được yêu cầu, nhưng theo sự hiểu biết của tôi, nếu lambda h:bị xóa, chức năng có hoạt động như cũ không?
schoon

2
@schoon Không, nó sẽ không hoạt động trong trường hợp này. Đây thực sự là một trường hợp rất thú vị để làm nổi bật ý tưởng về 'xác định phạm vi biến đổi' và làm cong hàm (về cơ bản dựa trên xác định phạm vi thay đổi). Lý do tại sao nó không hoạt động (trong ví dụ của tôi) là bởi vì returnsẽ cố gắng đánh giá kết quả trước khi trả về, và bởi vì đó là một loạt các biến, nó sẽ trả về một số giá trị float (hãy thử trả về một hàm và nó sẽ hoạt động). lambdachol biết rằng mã sau không nên được đánh giá và phạm vi của biến r cũng sẽ được giữ nguyên trong các hàm được trả về bởi make_cylinder...
DaveIdito

10

Chỉ muốn chỉ ra rằng bạn có thể làm điều này với 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)Thực hiện chính xác
R3ctor

1

Tôi biết mình đến bữa tiệc quá muộn, nhưng tôi nghĩ bạn có thể thấy giải pháp này thú vị.

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

Đây là tài liệu về cách partialhoạt động.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.