亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

functools部分如何做?

functools部分如何做?

慕無忌1623718 2019-12-07 15:02:44
我無法了解部分功能在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。我明白那個。但是我不明白incr2(4)。如何在部分函數中4傳遞獲取x?對我來說,4應該更換sum2。x和之間是什么關系4?
查看完整描述

3 回答

?
RISEBY

TA貢獻1856條經驗 獲得超5個贊

大致地,partial做這樣的事情(除了關鍵字args支持等):


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)


至于為什么需要它,有很多種情況。僅作為一個例子,假設您必須在一個預期有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))

Lambda:


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

在這三個中,partial最短和最快。(對于更復雜的情況,您可能需要自定義對象)。


查看完整回答
反對 回復 2019-12-07
?
一只甜甜圈

TA貢獻1836條經驗 獲得超5個贊

局部函數非常有用。


例如,在“管線式”函數調用序列中(其中一個函數的返回值是傳遞給下一個函數的參數)。


有時,這樣的管道中的函數需要單個參數,但是緊接其上游的函數返回兩個值。


在這種情況下,functools.partial可能允許您保持此功能管道完整。


這是一個特定的隔離示例:假設您要按每個數據點與目標之間的距離對一些數據進行排序:


# create some data

import random as RND

fnx = lambda: RND.randint(0, 10)

data = [ (fnx(), fnx()) for c in range(10) ]

target = (2, 4)


import math

def euclid_dist(v1, v2):

    x1, y1 = v1

    x2, y2 = v2

    return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)

要按距目標的距離對這些數據進行排序,您當然要做的是:


data.sort(key=euclid_dist)

但你不可阻擋-的排序方法的關鍵參數,只接受拍攝功能單一的參數。


因此,請改寫euclid_dist為帶有單個參數的函數:


from functools import partial


p_euclid_dist = partial(euclid_dist, target)

p_euclid_dist 現在接受一個參數,


>>> p_euclid_dist((3, 3))

  1.4142135623730951

因此,現在您可以通過傳遞sort方法的key參數的部分函數來對數據進行排序:


data.sort(key=p_euclid_dist)


# verify that it works:

for p in data:

    print(round(p_euclid_dist(p), 3))


    1.0

    2.236

    2.236

    3.606

    4.243

    5.0

    5.831

    6.325

    7.071

    8.602

又例如,函數的參數之一在外循環中更改,但在內循環的迭代過程中是固定的。通過使用部分函數,您無需在內部循環的迭代過程中傳遞其他參數,因為修改后的(部分函數)不需要此參數。


>>> from functools import partial


>>> def fnx(a, b, c):

      return a + b + c


>>> fnx(3, 4, 5)

      12

創建一個局部函數(使用關鍵字arg)


>>> pfnx = partial(fnx, a=12)


>>> pfnx(b=4, c=5)

     21

您還可以使用位置參數創建部分函數


>>> pfnx = partial(fnx, 12)


>>> pfnx(4, 5)

      21

但這會拋出(例如,創建帶有關鍵字參數的partial,然后使用位置參數調用)


>>> pfnx = partial(fnx, a=12)


>>> pfnx(4, 5)

      Traceback (most recent call last):

      File "<pyshell#80>", line 1, in <module>

      pfnx(4, 5)

      TypeError: fnx() got multiple values for keyword argument 'a'

另一個用例:使用python的multiprocessing庫編寫分布式代碼。使用Pool方法創建一個進程池:


>>> import multiprocessing as MP


>>> # create a process pool:

>>> ppool = MP.Pool()

Pool 有一個map方法,但是它只需要一個可迭代的方法,因此,如果您需要傳入帶有較長參數列表的函數,請將該函數重新定義為局部函數,以修復除一個以外的所有函數:


>>> ppool.map(pfnx, [4, 6, 7, 8])


查看完整回答
反對 回復 2019-12-07
  • 3 回答
  • 0 關注
  • 494 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號