相当于R的'do.call`在python中

时间:2016-08-02 14:09:17

标签: python r python-2.7

在python中是否有等价的R do.call

do.call(what = 'sum', args = list(1:10)) #[1] 55
do.call(what = 'mean', args = list(1:10)) #[1] 5.5

?do.call
# Description
# do.call constructs and executes a function call from a name or a function and a list of arguments to be passed to it.

4 个答案:

答案 0 :(得分:3)

没有内置功能,但构建等效内容非常容易。

您可以使用__builtin__(Python 2)或builtins(Python 3)模块从内置命名空间查找任何对象,然后将任意参数应用于*args**kwargs语法:

try:
    # Python 2
    import __builtin__ as builtins
except ImportError:
    # Python 3
    import builtins

def do_call(what, *args, **kwargs):
    return getattr(builtins, what)(*args, **kwargs)

do_call('sum', range(1, 11))

一般来说,我们不会在Python中这样做。如果必须将字符串转换为函数对象,通常首选构建自定义字典:

functions = {
    'sum': sum,
    'mean': lambda v: sum(v) / len(v),
}

然后从该字典中查找函数:

functions['sum'](range(1, 11))

这使您可以严格控制动态代码可用的名称,防止用户通过调用内置函数来破坏他们的破坏性或破坏性效果。

答案 1 :(得分:3)

do.call几乎相当于Python中的splat operator

def mysum(a, b, c):
    return sum([a, b, c])

# normal call:
mysum(1, 2, 3)

# with a list of arguments:
mysum(*[1, 2, 3])

请注意,我必须定义自己的sum函数,因为Python的sum已经期望list作为参数,因此您的原始代码将只是

sum(range(1, 11))

R有另一个特点:do.call在内部执行第一个参数的函数查找。这意味着即使它是一个字符串而不是一个实际的函数,它也能找到该函数。上面的Python等价物不会这样做 - 请参阅Martijn的解决方案。关于这一点的两件事:

  1. 它并非特定于R中的do.call。实际上,函数查找可能由match.fun在内部执行。
  2. 这是一个“太多魔术”的案例,我强烈反对在R中编写这样的代码,更不用说更强类型的语言了:它颠覆了类型系统,通常会导致错误。例如,当do.call是一个字符串时,what的R文档对于执行什么操作非常模糊。例如,鉴于其描述,期望do.call('base::sum', list(1, 2))应该起作用是合理的。唉,它没有。

答案 2 :(得分:0)

与先前的答案相似,但是为什么这么复杂?

def do_call(which, args=None, kwargs = None):
    if args is None and kwargs is not None:
        return which(**kwargs)
    elif args is not None and kwargs is None:
        return which(*args)
    else:
        return which(*args, **kwargs)

Python的sum与R的sum不同(1个预期参数列表与 任意预期R中有许多论点。因此,我们定义了自己的总和(mysum) 其行为与R的sum类似。我们以类似的方式定义mymean

def mysum(*args):
    return sum(args)

def mymean(*args):
    return sum(args)/len(args)

现在,我们可以在Python中重新创建您的示例-作为R函数调用的合理1:1转换。

do_call(what = mymean, args=[1, 2, 3])
## 2.0
do_call(what = mysum, args=[1, 2, 3])
## 6

对于带有参数名称的函数,我们对kwargs使用dict,其中参数 名称是字典的键(作为字符串),其值是值。

def myfunc(a, b, c):
    return a + b + c

do_call(what = myfunc, kwargs={"a": 1, "b": 2, "c": 3})
## 6

# we can even mix named and unnamed parts
do_call(what = myfunc, args = [1, 2], kwargs={"c": 3})
## 6

答案 3 :(得分:0)

我们永远不会在打字方面见得面目全非。感谢您分享您的观点。我认为有可能通过辩论而不必说“你错了”

您是否尝试过,“您的*位置错误”,这对个人的敌意较少。或者,“您可能要考虑...。”

如果您可以更改方法,我很乐意进一步考虑您的观点。