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)
Joan Venge
sumber

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 )
S.Lott
sumber
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))
Dave
sumber
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))
batal
sumber
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()

Jochen Ritzel
sumber
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?)

denis
sumber
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
Shital Shah
sumber
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)
Stefan Gruenwald
sumber
Bagaimanapun, seseorang perlu melakukan lebih dari sekadar menyerahkan fungsi ke penutupan lainnya adalah cara yang harus ditempuh.
jake77