Truyền hàm với đối số cho hàm khác trong Python?


203

Có thể truyền các hàm có đối số cho hàm khác trong Python không?

Nói cho một cái gì đó như:

def perform(function):
    return function()

Nhưng các hàm được truyền sẽ có các đối số như:

action1()
action2(p)
action3(p,r)

Câu trả lời:


289

Bạn có hiểu cái này không?

def perform( fun, *args ):
    fun( *args )

def action1( args ):
    something

def action2( args ):
    something

perform( action1 )
perform( action2, p )
perform( action3, p, r )

10
Những gì về tham số được đặt tên? Đó là, def action1(arg1, arg2=None, arg3=None)làm thế nào bạn có thể vượt qua một đối số mà bạn dự định được gán cho arg3, ví dụ?
ChaimKut

6
thực hiện (vui vẻ, ** args), xem stackoverflow.com/questions/8954746/
triệt

Điều gì nếu performaction1, action2trên các tập tin khác nhau? @
S.Lott

@alper nhập chúng
pfabri

122

Đây là những gì lambda dành cho:

def Perform(f):
    f()

Perform(lambda: Action1())
Perform(lambda: Action2(p))
Perform(lambda: Action3(p, r))

7
Ngoài ra vì tò mò, bạn có thể vui lòng cho tôi biết tại sao lambdas không tốt cho trường hợp này?
Joan Venge

11
lambdas là một trong những tính năng tốt nhất của ngôn ngữ lập trình tốt. Thật không may, việc triển khai Python bị hạn chế nghiêm trọng. trong trường hợp này, tuy nhiên, chúng hoàn toàn phù hợp
Javier

3
Tôi thấy rằng cú pháp hạn chế gần như mờ đục; họ khó giải thích cho n00bz. Vâng, họ làm việc ở đây, và các tính năng khó hiểu của cú pháp không có. Đây có lẽ - có lẽ - ví dụ duy nhất tôi từng thấy về lambda không tối nghĩa.
S.Lott

11
Vì vậy, bạn có thể truy xuất kết quả của hàm đã qua, sẽ không tốt hơn nếu Performance () được gọi là "return f ()" thay vì chỉ gọi f ().
mhawke

Tôi nghĩ rằng phiên bản lambda khá gọn gàng, nhưng kỳ lạ là trong các thử nghiệm tôi chạy, việc gọi các hàm qua lambda chậm hơn so với phương thức fn (* args) được thảo luận trong một câu trả lời khác.
Richard Shepherd

39

Bạn có thể sử dụng chức năng một phần từ funcools như vậy.

from functools import partial

def perform(f):
    f()

perform(Action1)
perform(partial(Action2, p))
perform(partial(Action3, p, r))

Cũng hoạt động với các từ khóa

perform(partial(Action4, param1=p))

1
functools.partialcũng linh hoạt hơn nếu performcần bàn giao thêm thông số f. Ví dụ, người ta có thể gọi perform(partial(Action3, p))perform(f)có thể làm một cái gì đó như f("this is parameter r").
Robert

13

Sử dụng funcools.partial, không lambdas! Và ofc Performance là một chức năng vô dụng, bạn có thể chuyển trực tiếp các chức năng.

for func in [Action1, partial(Action2, p), partial(Action3, p, r)]:
  func()


3
Nó phụ thuộc vào việc bạn có muốn đánh giá các đối số tại trang gọi của Thực hiện hay không.
Dave

6

(vài tháng sau) một ví dụ thực tế nhỏ trong đó lambda rất hữu ích, một phần là không:
giả sử bạn muốn có các mặt cắt 1 chiều khác nhau thông qua chức năng 2 chiều, giống như các lát cắt qua một dãy đồi.
quadf( x, f )mất 1-d fvà gọi nó cho nhiều x.
Để gọi nó là cắt dọc tại y = -1 0 1 và cắt ngang tại x = -1 0 1,

fx1 = quadf( x, lambda x: f( x, 1 ))
fx0 = quadf( x, lambda x: f( x, 0 ))
fx_1 = quadf( x, lambda x: f( x, -1 ))
fxy = parabola( y, fx_1, fx0, fx1 )

f_1y = quadf( y, lambda y: f( -1, y ))
f0y = quadf( y, lambda y: f( 0, y ))
f1y = quadf( y, lambda y: f( 1, y ))
fyx = parabola( x, f_1y, f0y, f1y )

Theo tôi biết, partialkhông thể làm điều này -

quadf( y, partial( f, x=1 ))
TypeError: f() got multiple values for keyword argument 'x'

(Làm thế nào để thêm thẻ numpy, một phần, lambda vào đây?)


5

Đây được gọi là chức năng một phần và có ít nhất 3 cách để làm điều này. Cách ưa thích của tôi là sử dụng lambda vì nó tránh được sự phụ thuộc vào gói bổ sung và ít dài dòng nhất. Giả sử bạn có một hàm add(x, y)và bạn muốn chuyển add(3, y)đến một số hàm khác làm tham số sao cho hàm kia quyết định giá trị cho y.

Sử dụng lambda

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# run example
def main():
    f = lambda y: add(3, y)
    result = runOp(f, 1) # is 4

Tạo Wrapper của riêng bạn

Ở đây bạn cần tạo một hàm trả về hàm một phần. Điều này rõ ràng là dài dòng hơn nhiều.

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# declare partial function
def addPartial(x):
    def _wrapper(y):
        return add(x, y)
    return _wrapper

# run example
def main():
    f = addPartial(3)
    result = runOp(f, 1) # is 4

Sử dụng một phần từ funcools

Điều này gần như giống hệt như lambdahiển thị ở trên. Vậy thì tại sao chúng ta cần điều này? Có vài lý do . Nói tóm lại, partialcó thể nhanh hơn một chút trong một số trường hợp (xem phần triển khai của nó ) và bạn có thể sử dụng nó để ràng buộc sớm so với ràng buộc muộn của lambda.

from functools import partial

# generic function takes op and its argument
def runOp(op, val):
    return op(val)

# declare full function
def add(x, y):
    return x+y

# run example
def main():
    f = partial(add, 3)
    result = runOp(f, 1) # is 4

1

Đây là một cách để làm điều đó với một đóng cửa:

    def generate_add_mult_func(func):
        def function_generator(x):
            return reduce(func,range(1,x))
        return function_generator

    def add(x,y):
        return x+y

    def mult(x,y):
        return x*y

    adding=generate_add_mult_func(add)
    multiplying=generate_add_mult_func(mult)

    print adding(10)
    print multiplying(10)

Trong mọi trường hợp, người ta cần phải làm nhiều hơn là chỉ truyền một chức năng cho một đóng khác là cách để đi.
jake77
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.