functools.partial和类似lambda之间的区别?

时间:2012-08-06 12:36:09

标签: python lambda partial functools

在Python中,假设我有一个函数f,我希望传递一些辅助参数(为简单起见,它只是第一个保持变量的参数)。

这两种方式(如果有的话)之间有什么区别?

# Assume secondary_args and secondary_kwargs have been defined

import functools

g1 = functools.partial(f, *secondary_args, **secondary_kwargs)
g2 = lambda x: f(x, *secondary_args, **secondary_kwargs)

例如,在doc page for partial中,有这样的引用:

  类中定义的

partial对象的行为类似于静态方法,并且在实例属性查找期间不会转换为绑定方法。

如果用于从提供给类的参数(在构造函数中或稍后通过函数)中创建类方法,lambda方法是否会受此影响?

5 个答案:

答案 0 :(得分:12)

  1. lambda函数与标准函数具有相同的类型,因此它的行为类似于实例方法。

  2. 您的示例中的partial对象可以像这样调用:

    g1(x, y, z)
    

    导致此调用(无效的Python语法,但您明白了):

    f(*secondary_args, x, y, z, **secondary_kwargs)
    

    lambda只接受一个参数并使用不同的参数顺序。 (当然这两个差异都可以克服 - 我只是回答你给出的两个版本之间的差异。)

  3. 执行partial对象的速度略快于执行等效lambda

答案 1 :(得分:0)

我认为类方法只适用于在类定义期间分配的函数。稍后分配的功能不会被特别处理。

除此之外,我个人赞成lambdas,因为它们更常见,因此使代码更容易理解。

class Foo(object):
    def __init__(self, base):
        self.int = lambda x:int(x, base)

print Foo(4).int('11')

答案 2 :(得分:0)

是的,lambda将“受此影响”。 partial没有这个问题,因为它是一个调用运算符重载的对象,而不是一个真正的函数。

但是在类定义中使用这样的lambda只是误用。

答案 3 :(得分:0)

部分不仅比已经说过的等效lambda快约20%,而且它们直接引用它们起作用。在lambdas中,函数在函数体内被“埋葬”。

=>如果您只需要解决延迟评估一个函数的问题,直到知道所有参数,那么使用partials。与将调用埋入匿名函数(即lambdas)相比,你将拥有更好的内省方法。

答案 4 :(得分:0)

摘要

在常见情况下,lambdafunctools.partial之间的实用差异似乎是

  • functools.partial需要导入,lambda不需要导入。
  • 仅通过打印创建的函数,即可看到用functools.partial创建的函数的函数定义。用lambda创建的函数应该用inspect.getsource()检查。

对于lambdafunctools.partial

,这些发现实际上相同
  • 速度
  • 追踪

速度(lambda与functools.partial)

我认为测试和真实数据要比猜测哪个比另一个要快要大得多。

看起来lambdafunctools.partial之间没有 没有速度差异的统计证明 。我用不同的重复次数进行了不同的测试,每次得到的结果都略有不同。三种方法中的任何一种都可能是最快的。速度相同,置信度为95%(2 sigma)。这是一些数值结果*

# When functions are defined beforehand
In [1]: timeit -n 1000 -r 1000 f_partial(data)
23.6 µs ± 2.92 µs per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

In [2]: timeit -n 1000 -r 1000 f_lambda(data)
22.6 µs ± 2.6 µs per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

# When function is defined each time again
In [3]: timeit -n 1000 -r 1000 (lambda x: trim_mean(x, 0.1))(data)
22.6 µs ± 1.98 µs per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

In [4]: timeit -n 1000 -r 1000 f_lambda = lambda x: trim_mean(x, 0.1); f_lambda(data)
23.7 µs ± 3.89 µs per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

In [5]: timeit -n 1000 -r 1000 f_partial = partial(trim_mean, proportiontocut=0.1); f_partial(data)
24 µs ± 3.38 µs per loop (mean ± std. dev. of 1000 runs, 1000 loops each)

追踪

我还尝试使用插入了字符串元素的list运行f_lambdaf_partial,并且回溯是相等的(当然,除了第一个条目之外)。所以那里没有区别。

检查源代码

  • 仅通过打印创建的函数,即可看到用functools.partial创建的函数的函数定义。用lambda创建的函数应该用inspect.getsource()检查。
# Can be inspected with just printing the function
In [1]: f_partial
Out[1]: functools.partial(<function trim_mean at 0x000001463262D0D0>, proportiontocut=0.1)

In [2]: print(f_partial)
functools.partial(<function trim_mean at 0x000001463262D0D0>, proportiontocut=0.1)

# Lambda functions do not show the source directly
In [3]: f_lambda
Out[3]: <function __main__.<lambda>(x)>

# But you can use inspect.getsource()
In [4]: inspect.getsource(f_lambda)
Out[4]: 'f_lambda = lambda x: trim_mean(x, 0.1)\n'

# This throws a ValueError, though.
In [5]: inspect.getsource(f_partial)

附录

*测试中使用的设置

from functools import partial
from scipy.stats import trim_mean
import numpy as np
data = np.hstack((np.random.random(1000), np.random.random(50)*25000))

f_lambda = lambda x: trim_mean(x, 0.1)
f_partial = partial(trim_mean, proportiontocut=0.1)

测试是在Python 3.7.3 64位(Windows 10)上进行的。