如何用另一个函数调用具有任意参数的函数?

问题描述:

我想知道我怎么会去这样做这样的事情(在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

您已经接近了,您只需要在调用内部函数时在元组前添加一个*(或者在关键字参数的字典前加**)。这被称为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

这里有一种方法:

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