2014-09-22 195 views
0

我想知道我怎麼會去這樣做這樣的事情(在Python 2):如何用另一個函數調用具有任意參數的函數?

def myFunction(fn, params): 
    return ("You called " + fn.__name__ + "(" + str(params) ")" + 
     " and got " + str(fn(params))) 

說我有一對夫婦的功能:

def doSomething(s): 
    # manipulation 
    return s 

def doAnotherThing(someInt, someOtherInt, someString): 
    # do something with them 
    return someValue 

我想成爲能夠撥打myFunction(doSomething, "hello"),並獲得You called doSomething("hello") and got "something"。這種方法似乎適用於採用單一輸入的函數,但我無法讓它適用於需要多個輸入的函數,例如調用myFunction(doAnotherThing, (myInt, myOtherInt, myString))。我想我需要做一些涉及***的事情,以便我可以任意使用關鍵字而不是tuple,但我不太確定如何去做。

+1

你正在尋找一個[裝飾](http://simeonfranklin.com/blog/2012/jul/1/ python-decorators-in-12-steps /),我建議讀一下他們做你想做的事情。 – Jack 2014-09-22 18:30:09

回答

3

您已經接近了,您只需要在調用內部函數時在元組前添加一個*(或者在關鍵字參數的字典前加**)。這被稱爲argument unpacking

def wrapper(fn, params, keyword_params): 
    return fn(*params, **keyword_params) 

def myfunc(a, b, c=0): 
    return (a + b)/c 

wrapper(myfunc, (2, 5), {'c': 3}) 

您還可以使用arbitrary argument lists來潛在地簡化包裝函數。這將允許您自動打包額外的參數以供給內部函數,而無需將它們預先打包到元組和字典中。只是使用第一種方法實際上將打破單參數的實現,爲*操作

def wrapper(fn, *params, **keyword_params): # Note the asterisks 
    return fn(*params, **keyword_params) 

def myfunc(a, b, c=1): 
    return (a + b)/c 

wrapper(myfunc, 2, 5, c=3) # Nicer function call 

注期望一個迭代器來解壓。因此,您必須始終預先打包參數或在wrapper函數中添加一些類型檢查。

def wrapper(fn, params): 
    return fn(*params) 

def myfunc(a): 
    return 2*a 

wrapper(myfunc, 2) 
# TypeError: myfunc() argument after * must be a sequence, not int 

wrapper(myfunc, (2,)) # Package the argument in a single-element tuple 
# 4 

第二種方法沒有這個問題。

+0

你也可以在'wrapper'的定義中包含'*'s,這樣它的調用看起來就像是嵌套的:'def wrapper(fn,* params,** keyword_params)',然後你可以調用'包裝(myfunc,2,5,c = 3)'。 – 2014-09-22 18:35:30

+0

@MarkReed謝謝,添加到答案。 – 2014-09-22 18:43:54

+0

@RogerFan可能也想明確地將打印內容添加到你的'wrapper'裝飾器中。 – 2014-09-22 18:45:24

0

這裏有一種方法:

def myFunction(fn, *params): 
    return ("You called " + fn.__name__ + str(params) + 
     " and got " + str(fn(*params))) 

import math 
print myFunction(math.sqrt, 4) 

print myFunction(open, '/etc/passwd', 'r') 
print myFunction(lambda x: x+1, 41) 

結果:

You called sqrt(4,) and got 2.0 
You called open('/etc/passwd', 'r') and got <open file '/etc/passwd', mode 'r' at 0x7f20e9cb65d0> 
You called <lambda>(41,) and got 42 
相關問題