Melewati fungsi dengan argumen ke fungsi lain dengan Python?


205

Apakah mungkin untuk meneruskan fungsi dengan argumen ke fungsi lain dengan Python?

Katakan sesuatu seperti:

def perform(function):
    return function()

Tetapi fungsi yang akan dilewati akan memiliki argumen seperti:

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

Jawaban:


291

Maksudmu ini?

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

def action1( args ):
    something

def action2( args ):
    something

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

10
Bagaimana dengan parameter bernama? Yaitu def action1(arg1, arg2=None, arg3=None), bagaimana Anda bisa memberikan argumen yang ingin Anda berikan ke arg3, misalnya?
ChaimKut

6
perform (fun, ** args), lihat stackoverflow.com/questions/8954746/…
Mannaggia

Bagaimana jika performdan action1, action2pada file yang berbeda? @ S.Lott
alper

@alper impor mereka
pfabri

122

Inilah tujuan dari lambda:

def Perform(f):
    f()

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

7
Juga karena penasaran, dapatkah Anda memberi tahu saya mengapa lambdas tidak baik untuk kasus ini?
Joan Venge

11
lambdas adalah salah satu fitur terbaik dari bahasa pemrograman yang baik. Sayangnya, implementasi Python sangat terbatas. dalam hal ini, bagaimanapun, mereka sangat cocok
Javier

3
Saya menemukan bahwa sintaks terbatas hampir buram; mereka sulit dijelaskan kepada n00bz. Ya, mereka memang bekerja di sini, dan fitur sintaks yang membingungkan tidak ada. Ini - mungkin - satu-satunya contoh yang saya lihat tentang lambda yang tidak jelas.
S.Lott

11
Agar Anda dapat mengambil hasil fungsi yang diteruskan, bukankah lebih baik jika Perform () disebut "return f ()" daripada hanya memanggil f ().
mhawke

Saya berpikir bahwa versi lambda cukup rapi, tetapi anehnya dalam tes yang saya jalankan ternyata lebih lambat untuk memanggil fungsi melalui lambda daripada dengan metode fn (* args) yang dibahas dalam jawaban lain.
Richard Shepherd

39

Anda dapat menggunakan fungsi parsial dari functools seperti itu.

from functools import partial

def perform(f):
    f()

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

Juga berfungsi dengan kata kunci

perform(partial(Action4, param1=p))

1
functools.partialjuga lebih fleksibel jika performperlu menyerahkan parameter lebih lanjut f. Misalnya, seseorang dapat menelepon perform(partial(Action3, p))dan perform(f)melakukan sesuatu seperti f("this is parameter r").
Robert

13

Gunakan functools.partial, bukan lambdas! Dan ofc Perform adalah fungsi yang tidak berguna, Anda dapat menyebarkan fungsi secara langsung.

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


3
Itu tergantung pada apakah Anda ingin argumen dievaluasi di situs panggilan Perform atau tidak.
Dave

6

(berbulan-bulan kemudian) contoh nyata kecil di mana lambda berguna, sebagian tidak:
katakanlah Anda ingin berbagai penampang 1 dimensi melalui fungsi 2 dimensi, seperti irisan melalui deretan bukit.
quadf( x, f )mengambil 1-d fdan menyebutnya untuk berbagai x.
Untuk menyebutnya pemotongan vertikal pada y = -1 0 1 dan pemotongan horizontal pada 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 )

Sejauh yang saya tahu, partialtidak bisa melakukan ini -

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

(Bagaimana cara menambahkan tag numpy, partial, lambda ke ini?)


5

Ini disebut fungsi parsial dan setidaknya ada 3 cara untuk melakukan ini. Cara favorit saya adalah menggunakan lambda karena menghindari ketergantungan pada paket tambahan dan paling tidak bertele-tele. Asumsikan Anda memiliki fungsi add(x, y)dan Anda ingin meneruskan add(3, y)ke beberapa fungsi lain sebagai parameter sehingga fungsi lainnya menentukan nilai y.

Gunakan 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

Buat Wrapper Anda Sendiri

Di sini Anda perlu membuat fungsi yang mengembalikan fungsi parsial. Ini jelas jauh lebih bertele-tele.

# 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

Gunakan sebagian dari functools

Ini hampir identik dengan yang lambdaditunjukkan di atas. Lalu mengapa kita membutuhkan ini? Ada beberapa alasan . Singkatnya, partialmungkin sedikit lebih cepat dalam beberapa kasus (lihat implementasinya ) dan Anda dapat menggunakannya untuk pengikatan awal vs.

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

Berikut cara untuk melakukannya dengan penutupan:

    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)

Bagaimanapun, seseorang perlu melakukan lebih dari sekadar menyerahkan fungsi ke penutupan lainnya adalah cara yang harus ditempuh.
jake77
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.