我不能得到我的头如何部分工作在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的关系是什么?


当前回答

另外值得一提的是,当部分函数传递给另一个函数时,我们想要“硬编码”一些参数,那应该是最右边的参数

def func(a,b):
    return a*b
prt = partial(func, b=7)
    print(prt(4))
#return 28

但如果我们做同样的事情,只是改变一个参数

def func(a,b):
    return a*b
 prt = partial(func, a=7)
    print(prt(4))

它会抛出错误, "TypeError: func()获得了参数'a'的多个值"

其他回答

在我看来,这是在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做的事情是这样的(除了关键字参数支持等):

def partial(func, *part_args):
    def wrapper(*extra_args):
        args = list(part_args)
        args.extend(extra_args)
        return func(*args)

    return wrapper

因此,通过调用partial(sum2,4),您创建了一个新函数(准确地说,是一个可调用函数),它的行为与sum2类似,但少了一个位置参数。缺少的参数总是被4代替,因此partial(sum2, 4)(2) == sum2(4,2)

至于为什么需要它,有各种各样的情况。举个例子,假设你必须将一个函数传递到有两个参数的地方:

class EventNotifier(object):
    def __init__(self):
        self._listeners = []

    def add_listener(self, callback):
        ''' callback should accept two positional arguments, event and params '''
        self._listeners.append(callback)
        # ...

    def notify(self, event, *params):
        for f in self._listeners:
            f(event, params)

但是你已经拥有的函数需要访问第三个context对象来完成它的工作:

def log_event(context, event, params):
    context.log_event("Something happened %s, %s", event, params)

因此,有几个解决方案:

自定义对象:

class Listener(object):
   def __init__(self, context):
       self._context = context

   def __call__(self, event, params):
       self._context.log_event("Something happened %s, %s", event, params)


 notifier.add_listener(Listener(context))

λ:

log_listener = lambda event, params: log_event(context, event, params)
notifier.add_listener(log_listener)

分音:

context = get_context()  # whatever
notifier.add_listener(partial(log_event, context))

在这三种方法中,偏微分是最短和最快的。 (对于更复杂的情况,您可能需要一个自定义对象)。

另外值得一提的是,当部分函数传递给另一个函数时,我们想要“硬编码”一些参数,那应该是最右边的参数

def func(a,b):
    return a*b
prt = partial(func, b=7)
    print(prt(4))
#return 28

但如果我们做同样的事情,只是改变一个参数

def func(a,b):
    return a*b
 prt = partial(func, a=7)
    print(prt(4))

它会抛出错误, "TypeError: func()获得了参数'a'的多个值"

简而言之,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()

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