fn.py 源碼之 func

func.py

func 模塊主要實現兩個函數 F 和 curriedpython

contents

F

核心函數,包裝爲一個偏函數(partial),經過操做符 >> << 實現鏈式操做app

class F(object):
    __slots__ = "f",

    def __init__(self, f = identity, *args, **kwargs):
        self.f = partial(f, *args, **kwargs) if any([args, kwargs]) else f

 @classmethod
    def __compose(cls, f, g):
        return cls(lambda *args, **kwargs: f(g(*args, **kwargs)))

    def __ensure_callable(self, f):
        return self.__class__(*f) if isinstance(f, tuple) else f

    def __rshift__(self, g):
        """Overload >> operator for F instances"""
        return self.__class__.__compose(self.__ensure_callable(g), self.f)

    def __lshift__(self, g):
        """Overload << operator for F instances"""
        return self.__class__.__compose(self.f, self.__ensure_callable(g))

    def __call__(self, *args, **kwargs):
        """Overload apply operator"""
        return self.f(*args, **kwargs)
''' >>> func = F() << (_ + 10) << (_ + 5) >>> print(func(10)) 25 >>> func = F() >> (filter, _ < 6) >> sum >>> print(func(range(10))) 15 '''
複製代碼

經過 __compose 組合調用,將 >> << 操做符左右對象從新生成 F 對象
__ensure_callable 處理 tuple 類型的參數,好比ide

func = F(operator.add, 3) >> (operator.mul, 5)
print func(2)

# 25
複製代碼

curried

柯里化裝飾器
被裝飾函數調用時,先展開 partial 查看已經綁定的參數個數。
若是和函數初始定義時個數一致,調用函數並返回值;
若是少於函數定義時的個數,使用 partial 包裝後返回 curried。函數

def curried(func):
 @wraps(func)
    def _curried(*args, **kwargs):
        f = func
        count = 0
        while isinstance(f, partial):
            if f.args:
                count += len(f.args)
            # parial 保存有 func 屬性
            f = f.func
        # while 結束,f 變爲最原始未被裝飾的函數
        # getargspec 獲取最初的被裝飾函數的參數信息
        spec = getargspec(f)

        if count == len(spec.args) - len(args):
            return func(*args, **kwargs)

        return curried(partial(func, *args, **kwargs))
    return _curried
""" >>> @curried ... def sum5(a, b, c, d, e): ...  return a + b + c + d + e ... >>> sum5(1)(2)(3)(4)(5) 15 >>> sum5(1, 2, 3)(4, 5) 15 """
複製代碼

curried 實質是對 partial 嵌套調用的一個包裝:spa

@curried
def sum3(a, b, c):
    return a + b + c
''' >>> print sum3(1)(2)(3) >>> print partial(partial(sum3, 1), 2)(3) 6 6 '''
複製代碼

版權

做者:bigfish
許可協議:許可協議 知識共享署名-非商業性使用 4.0 國際許可協議code

相關文章
相關標籤/搜索