天天看點

【Python子產品】functools —— 作用于可調用對象的高階函數集合

    英文原文出自:https://docs.python.org/2/library/functools.html

    functools 是一系列高階函數的集合,這些函數可以接受其他函數作為參數或者傳回其他函數。一般說來,凡是可被調用的對象,都可以當成這個子產品的作用對象。

    functools 子產品定義了下面的一系列函數:

functools.

cmp_to_key

(func)

    cmp_to_key可以将老式風格的比較函數轉換成比較關鍵字函數。這個函數用在接收比較關鍵字函數作為參數的函數中(比如 

sorted()

min()

max()

heapq.nlargest()

heapq.nsmallest()

itertools.groupby()

)。因為在Python3中不再支援老式風格的比較函數,這個函數也常被當成把python2的函數轉向python3的工具。

    老式風格的比較函數是指,接收兩個參數進行比較,如果一個前者小于後者傳回一個負數,前者等于後者傳回0,前者大于後者傳回一個正數。比較關鍵字函數是指接收一個參數,傳回另外一個結果作為排序的關鍵字。

    應用舉例:

from functools import cmp_to_key
def cmfunc(x,y):
    if x>y:
        return 1
    elif x==y:
        return 0
    else:
        return -1

seq=[2,1,4,5,3]
seq = sorted(seq,key=cmp_to_key(cmfunc))
for r in seq:
    print r
           

          輸出結果:

[email protected]:~/projects/PythonTs$ python cmp_to_keyTs.py 
1
2
3
4
5
           

         檢視更多排序的例子或者相關文檔請檢視 Sorting HOW TO .

functools.

total_ordering

(cls)

   如果一個類中含有一個以上的用于比較的方法,這個類級别的修飾器會補充剩下的部分用于比較的方法,它簡化了在類中定義比較方法的繁重工作。

   這個被修飾的類必須定義以下方法之一 

__lt__()

__le__()

__gt__()

, or 

__ge__()。另外,該類也必須實作

__eq__()

 方法。

   應用舉例:

@total_ordering
class Student:
    def __eq__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) ==
                (other.lastname.lower(), other.firstname.lower()))
    def __lt__(self, other):
        return ((self.lastname.lower(), self.firstname.lower()) <
                (other.lastname.lower(), other.firstname.lower()))
           

           我們定義了Student類,隻聲明了__eq__和__lt__方法,當Student類被total_ordering修飾後,使用dir檢視Student的屬性,其他剩餘的比較函數都被自動定義:

>>> from total_orderingTs import Student
>>> dir(Student)
['__doc__', '__eq__', '__ge__', '__gt__', '__le__', '__lt__', '__module__']
>>> 
           

functools.

reduce

(function, iterable[, initializer])

   這個函數和reduce的功能一樣,它在functools子產品建立隻是為了使python3向前相容。

  使用舉例:

from functools import reduce
def add(x,y):
    return x+y

print reduce(add,[1,2,3,4,5])
           

           reduce的功能是将list中的前兩個值作為參數傳給add函數,然後将add的結果和第三個值再次傳給add函數,以此類推,最終傳回一個結果:

[email protected]:~/projects/PythonTs$ python reduceTs.py 
15
           

functools.

partial

(func[,*args][, **keywords])¶

         傳回一個新的partial(偏函數)對象,partial被調用時就像傳給它的func函數帶着參數args和keywords被調用一樣。如果func也附帶了自己的參數,那麼它的參數将被追加至args或者keywords中。大概等價于以下代碼:

def partial(func, *args, **keywords):
    def newfunc(*fargs, **fkeywords):
        newkeywords = keywords.copy()
        newkeywords.update(fkeywords)
        return func(*(args + fargs), **newkeywords)
    newfunc.func = func
    newfunc.args = args
    newfunc.keywords = keywords
    return newfun
           

          partial()通過"當機"一個函數的部分參數而擷取一個偏函數對象,相當于簡化了原函數的簽名。比如說 partial()可以建立一個行為類似于base為2的int()函數:

>>> from functools import partial
>>> basetwo = partial(int, base=2)
>>> basetwo.__doc__ = 'Convert base 2 string to an int.'
>>> basetwo('10010')
18
           

         應用舉例:

from functools import partial
def add(x,y,z):
    return x+y+z

newadd=partial(add,y=1,z=2)
print newadd(3)
print newadd(55555)
           

          我們用partial定義新的函數newadd,但是簡化了參數清單,隻傳入一個參數即可。

functools.

update_wrapper

(wrapper, wrapped[, assigned][, updated])

       使修飾函數更加符合被修飾函數。該函數中的後面可選參數是兩組元組,前者用來指定從被修飾函數中擷取哪些屬性給修飾函數,後者用來指定修飾函數中哪些屬性需要更新和被修飾函數一緻。這些參數的預設值都是子產品級别的限制,如WRAPPER_ASSIGNMENTS (在修飾函數中增加 __name__, __module__ 和 __doc__這些文檔屬性)和WRAPPER_UPDATES (更新修飾函數的__dict__屬性)

       這個函數最主要的用處就是用在裝飾器中。如果裝飾器中的修飾函數沒有被更新,裝飾器的傳回函數的中繼資料将會映射修飾函數而非被修飾函數。

functools.

wraps

(wrapped[, assigned][, updated])

    這個函數作為裝飾器,在定義修飾函數的時候可以很友善的激活update_wrapper。它等價于partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated)。       應用舉例:

from functools import wraps


def decoratorWithoutWraps(f):
    def wrapper_func(args):
        """wrapper doc"""
        return f(args)
    return wrapper_func

@decoratorWithoutWraps
def wrapped_func1(args):
    """wrapped1 doc"""
    pass

def decoratorWithWraps(f):
    @wraps(f)
    def wrapper_func():
        """wrapper doc"""
        return f()
    return wrapper_func

@decoratorWithWraps
def wrapped_func2():
    """wrapped2 doc"""
    pass

if __name__ =='__main__':
    #without @wraps
    print wrapped_func1.__name__
    print wrapped_func1.__doc__
    #with @wraps
    print wrapped_func2.__name__
    print wrapped_func2.__doc__
           

    執行結果:

[email protected]:~/projects/PythonTs$ python wrapperTs.py
wrapper_func
wrapper doc
wrapped_func2
wrapped2 doc
           

    對于修飾器函數前沒有使用@wraps的,列印出來的結果是定義的修飾器函數的__name__和__doc__,而對于修飾器前使用@wraps的,列印出來的是被修飾函數的 __name__和__doc__,顯然後者才是我們期望的。

 Github位置:

https://github.com/HymanLiuTS/PythonTs

克隆本項目:

git clone [email protected]:HymanLiuTS/PythonTs.git

擷取本文源代碼:

git checkout PL02