我不能得到我的头如何部分工作在functools。 我有以下代码从这里:

>>> sum = lambda x, y : x + y
>>> sum(1, 2)
3
>>> incr = lambda y : sum(1, y)
>>> incr(2)
3
>>> def sum2(x, y):
    return x + y

>>> incr2 = functools.partial(sum2, 1)
>>> incr2(4)
5

现在在队列中

incr = lambda y : sum(1, y)

我得到,无论我传递给incr的参数是什么,它都会作为y传递给lambda,它会返回sum(1, y)即1 + y。

我理解。但是我不明白这一点。

在偏函数中,4是如何作为x传递的?对我来说,4应该取代求和2。x和4的关系是什么?


当前回答

从机器学习的例子中加入了函数式编程的functools。Partial非常有用:

在同一数据集上构建多个模型

下面的例子展示了如何在同一个糖尿病数据集上拟合线性回归、支持向量机和随机森林回归模型,以预测目标并计算得分。

(部分)函数classify_diabetes()是通过curry(使用functools.partial())从函数classify_data()创建的。后面的函数不再需要传递数据,我们可以直接只传递模型类的实例。

from functools import partial
from sklearn.linear_model import LinearRegression
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import load_diabetes

def classify_data(data, model):
    reg = model.fit(data['data'], data['target'])
    return model.score(data['data'], data['target'])

diabetes = load_diabetes()
classify_diabetes = partial(classify_data, diabetes) # curry
for model in [LinearRegression(), SVR(), RandomForestRegressor()]:
    print(f'model {type(model).__name__}: score = {classify_diabetes(model)}')

# model LinearRegression: score = 0.5177494254132934
# model SVR: score = 0.2071794500005485
# model RandomForestRegressor: score = 0.9216794155402649

建立机器学习管道

在这里,函数pipeline()是用咖喱创建的,它已经使用StandardScaler()在拟合模型之前对数据进行预处理(缩放/规范化),如下面的例子所示:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

pipeline = partial(make_pipeline, StandardScaler()) # curry    
for model in [LinearRegression(), SVR(), RandomForestRegressor()]:
    print(f"model {type(model).__name__}: " \
          f"score = {pipeline(model).fit(diabetes['data'], diabetes['target'])\
                                 .score(diabetes['data'], diabetes['target'])}")

# model LinearRegression: score = 0.5177494254132934
# model SVR: score = 0.2071794500005446
# model RandomForestRegressor: score = 0.9180227193805106

其他回答

简而言之,partial为函数的参数提供默认值,否则这些参数将没有默认值。

from functools import partial

def foo(a,b):
    return a+b

bar = partial(foo, a=1) # equivalent to: foo(a=1, b)
bar(b=10)
#11 = 1+10
bar(a=101, b=10)
#111=101+10

偏导数可以用来生成一些预先赋值的输入参数的新派生函数

要了解一些在现实世界中使用偏分式的用法,请参考这里的这篇非常好的博客文章

这是一个简单但简洁的初学者示例,介绍了如何在re.search中使用partial来使代码更具可读性。Re.search方法的签名为:

search(pattern, string, flags=0) 

通过应用partial,我们可以创建多个版本的正则表达式搜索来满足我们的需求,例如:

is_spaced_apart = partial(re.search, '[a-zA-Z]\s\=')
is_grouped_together = partial(re.search, '[a-zA-Z]\=')

现在is_spaced_apart和is_grouped_together是派生自re.search的两个新函数,它们应用了pattern参数(因为pattern是re.search方法签名中的第一个参数)。

这两个新函数(可调用)的签名是:

is_spaced_apart(string, flags=0)     # pattern '[a-zA-Z]\s\=' applied
is_grouped_together(string, flags=0) # pattern '[a-zA-Z]\=' applied

这就是你如何在一些文本上使用这些partial函数:

for text in lines:
    if is_grouped_together(text):
        some_action(text)
    elif is_spaced_apart(text):
        some_other_action(text)
    else:
        some_default_action()

你可以参考上面的链接来更深入地了解这个主题,因为它涵盖了这个特定的例子和更多。

从机器学习的例子中加入了函数式编程的functools。Partial非常有用:

在同一数据集上构建多个模型

下面的例子展示了如何在同一个糖尿病数据集上拟合线性回归、支持向量机和随机森林回归模型,以预测目标并计算得分。

(部分)函数classify_diabetes()是通过curry(使用functools.partial())从函数classify_data()创建的。后面的函数不再需要传递数据,我们可以直接只传递模型类的实例。

from functools import partial
from sklearn.linear_model import LinearRegression
from sklearn.svm import SVR
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import load_diabetes

def classify_data(data, model):
    reg = model.fit(data['data'], data['target'])
    return model.score(data['data'], data['target'])

diabetes = load_diabetes()
classify_diabetes = partial(classify_data, diabetes) # curry
for model in [LinearRegression(), SVR(), RandomForestRegressor()]:
    print(f'model {type(model).__name__}: score = {classify_diabetes(model)}')

# model LinearRegression: score = 0.5177494254132934
# model SVR: score = 0.2071794500005485
# model RandomForestRegressor: score = 0.9216794155402649

建立机器学习管道

在这里,函数pipeline()是用咖喱创建的,它已经使用StandardScaler()在拟合模型之前对数据进行预处理(缩放/规范化),如下面的例子所示:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

pipeline = partial(make_pipeline, StandardScaler()) # curry    
for model in [LinearRegression(), SVR(), RandomForestRegressor()]:
    print(f"model {type(model).__name__}: " \
          f"score = {pipeline(model).fit(diabetes['data'], diabetes['target'])\
                                 .score(diabetes['data'], diabetes['target'])}")

# model LinearRegression: score = 0.5177494254132934
# model SVR: score = 0.2071794500005446
# model RandomForestRegressor: score = 0.9180227193805106

在我看来,这是在python中实现curry的一种方式。

from functools import partial
def add(a,b):
    return a + b

def add2number(x,y,z):
    return x + y + z

if __name__ == "__main__":
    add2 = partial(add,2)
    print("result of add2 ",add2(1))
    add3 = partial(partial(add2number,1),2)
    print("result of add3",add3(1))

结果是3和4。

这个答案更像是一个示例代码。以上所有答案都很好地解释了为什么应该使用partial。我将给出关于partial的观察和用例。

from functools import partial
 def adder(a,b,c):
    print('a:{},b:{},c:{}'.format(a,b,c))
    ans = a+b+c
    print(ans)
partial_adder = partial(adder,1,2)
partial_adder(3)  ## now partial_adder is a callable that can take only one argument

上述代码的输出应该是:

a:1,b:2,c:3
6

注意,在上面的例子中,返回了一个新的可调用对象,它将形参(c)作为参数。注意,它也是函数的最后一个参数。

args = [1,2]
partial_adder = partial(adder,*args)
partial_adder(3)

上述代码的输出也是:

a:1,b:2,c:3
6

注意,*用于解包非关键字参数,返回的可调用对象的参数与上面相同。

另一个观察结果是: 下面的示例演示了partial返回一个可调用对象,该对象将接受 未声明的形参(a)作为参数。

def adder(a,b=1,c=2,d=3,e=4):
    print('a:{},b:{},c:{},d:{},e:{}'.format(a,b,c,d,e))
    ans = a+b+c+d+e
    print(ans)
partial_adder = partial(adder,b=10,c=2)
partial_adder(20)

上述代码的输出应该是:

a:20,b:10,c:2,d:3,e:4
39

同样的,

kwargs = {'b':10,'c':2}
partial_adder = partial(adder,**kwargs)
partial_adder(20)

以上代码打印

a:20,b:10,c:2,d:3,e:4
39

我在使用Pool的时候不得不使用它。多处理模块的Map_async方法。你只能将一个参数传递给worker函数,所以我必须使用partial使我的worker函数看起来像一个只有一个输入参数的可调用对象,但实际上我的worker函数有多个输入参数。