functools partial はどのように機能しますか? 質問する

functools partial はどのように機能しますか? 質問する

partialがでどのように動作するのか理解できません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渡されることがわかります。ylambdasum(1, y)1 + y

それは理解しています。しかし、これは理解できませんでしたincr2(4)

4は部分関数でとして渡されるのでしょうかx? 私としては、4を に置き換える必要があります。とsum2の関係は何ですか?x4

ベストアンサー1

大まかに言うと、partial次のようなことを行います (キーワード引数のサポートなどは別として)。

def partial(func, *part_args):
    def wrapper(*extra_args):
        return func(*args, *extra_args)            
    return wrapper

したがって、 を呼び出すことで、partial(sum2, 4)のように動作するが位置引数が1つ少ない新しい関数(正確には呼び出し可能関数)を作成しますsum2。不足している引数は常に で置き換えられる4ため、partial(sum2, 4)(2) == sum2(4, 2)

なぜそれが必要なのかというと、さまざまなケースがあります。たとえば、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その機能を実行するために 3 番目のオブジェクトにアクセスする必要があります。

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))

これら 3 つのうち、partialは最も短く、最も高速です。(ただし、より複雑なケースでは、カスタム オブジェクトが必要になる場合があります)。

おすすめ記事