Bağımsız değişkenli işlevleri Python'da başka bir işleve mi geçiriyorsunuz?


205

Bağımsız değişkenli işlevleri Python'daki başka bir işleve geçirmek mümkün müdür?

Gibi bir şey söyle:

def perform(function):
    return function()

Ancak geçilecek işlevler aşağıdaki gibi argümanlara sahip olacaktır:

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

Yanıtlar:


291

Bunu mu diyorsun?

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

def action1( args ):
    something

def action2( args ):
    something

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

10
Adlandırılmış parametreler ne olacak? Yani, def action1(arg1, arg2=None, arg3=None)örneğin arg3'e atanmayı düşündüğünüz bir argümanı nasıl iletebilirsiniz?
ChaimKut

6
gerçekleştirmek (eğlenceli, ** argümanlar), bkz. stackoverflow.com/questions/8954746/…
Mannaggia

Ya performve action1, action2farklı dosyalarda? S.Lott
alper

@alper import them
pfabri

122

Lambda bunun için:

def Perform(f):
    f()

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

7
Ayrıca meraktan, lütfen bu dava için lambdaların neden iyi olmadığını söyleyebilir misiniz?
Joan Venge

11
lambdalar iyi programlama dillerinin en iyi özelliklerinden biridir. ne yazık ki, Python'un uygulaması ciddi şekilde sınırlıdır. Ancak bu durumda, mükemmel uyum
Javier

3
Sınırlı sözdiziminin neredeyse opak olduğunu düşünüyorum; n00bz'ye açıklamak zor. Evet, burada çalışıyorlar ve sözdiziminin kafa karıştırıcı özellikleri mevcut değil. Bu - belki de - belirsiz olmayan bir lambda için gördüğüm tek örnek.
S.Lott

11
Geçirilen işlevin sonucunu alabilmeniz için, Perform () işlevinin yalnızca f () öğesini çağırmak yerine "return f ()" olarak adlandırması daha iyi olmaz.
mhawke

Lambda versiyonunun oldukça düzgün olduğunu düşünüyorum, ama garip bir şekilde koştum testlerde lambda aracılığıyla işlevleri çağırmak başka bir cevapta tartışılan fn (* args) yönteminden daha yavaştı.
Richard Shepherd

39

Kısmi işlevi functools gibi kullanabilirsiniz.

from functools import partial

def perform(f):
    f()

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

Anahtar kelimelerle de çalışır

perform(partial(Action4, param1=p))

1
functools.partialdaha performfazla parametre iletilmesi gerektiğinde daha çok yönlüdür f. Örneğin, kişi arayabilir perform(partial(Action3, p))ve perform(f)böyle bir şey yapabilir f("this is parameter r").
Robert

13

Functools kullanın. Lambdas değil kısmi! Ve ofc Perform işe yaramaz bir işlevdir, işlevleri doğrudan aktarabilirsiniz.

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


3
Bu, argümanların Perform'in çağrı sitesinde değerlendirilmesini isteyip istemediğinize bağlıdır.
Dave

6

(aylar sonra) lambda'nın yararlı olduğu küçük bir gerçek örnek, kısmi değil:
2 boyutlu bir işlev boyunca, bir sıra tepeden gelen dilimler gibi çeşitli 1 boyutlu kesitler istediğinizi varsayalım.
quadf( x, f )bir 1-d alır fve çeşitli için çağırır x.
Bunu y = -1 0 1 dikey kesimler ve x = -1 0 1 yatay kesimler olarak adlandırmak için,

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 )

Bildiğim kadarıyla, partial bunu yapamam -

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

(Buna numpy, kısmi, lambda etiketleri nasıl eklenir?)


5

Buna kısmi işlevler denir ve bunu yapmanın en az 3 yolu vardır. En sevdiğim yol lambda kullanmaktır çünkü ekstra pakete bağımlılığı önler ve en az ayrıntılıdır. Bir fonksiyonunuz olduğunu ve diğer fonksiyonun değerine karar vereceği şekilde parametre olarak başka bir fonksiyona add(x, y)geçmek istediğinizi varsayın .add(3, y)y

Lambda kullan

# 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

Kendi Paketleyicinizi Yaratın

Burada kısmi işlevi döndüren bir işlev oluşturmanız gerekir. Bu çok daha ayrıntılı.

# 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

Functools'tan kısmi kullanın

Bu, lambdayukarıda gösterilenle hemen hemen aynıdır . Öyleyse neden buna ihtiyacımız var? Bunun birkaç nedeni var . Kısacası, partialbazı durumlarda biraz daha hızlı olabilir ( uygulanmasına bakın ) ve lambda'nın geç bağlanmasına karşı erken bağlanma için kullanabilirsiniz.

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

İşte bir kapatma ile yapmanın bir yolu:

    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)

Her halükarda, bir kişinin bir işlevi diğerine geçirmekten daha fazlasını yapması gerekir, kapanmanın yolu.
jake77
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.