Python標準模塊--functools
1 模塊簡介
functools,用于高階函數:指那些作用于函數或者返回其它函數的函數,通常只要是可以被當做函數調用的對象就是這個模塊的目標。
在Python 2.7 中具備如下方法,
cmp_to_key,將一個比較函數轉換關鍵字函數;
partial,針對函數起作用,并且是部分的;
reduce,與python內置的reduce函數功能一樣;
total_ordering,在類裝飾器中按照缺失順序,填充方法;
update_wrapper,更新一個包裹(wrapper)函數,使其看起來更像被包裹(wrapped)的函數;
wraps,可用作一個裝飾器,簡化調用update_wrapper的過程;
2 模塊使用
2.1 cmp_to_key
將老式的比較函數(comparison function)轉換為關鍵字函數(key function),與接受key function的工具一同使用(例如sorted,min,max,heapq.nlargest,itertools.groupby),該函數主要用于將程序轉換成Python 3格式的,因為Python 3中不支持比較函數。
比較函數是可調用的,接受兩個參數,比較這兩個參數并根據他們的大小關系返回負值、零或者正值中的一個。關鍵字函數也是可調用的,接受一個參數,同時返回一個可以用作排序關鍵字的值。
from functools import cmp_to_key
def compare(ele1,ele2):
return ele2 - ele1
a = [2,3,1]
print sorted(a, key = cmp_to_key(compare))</code></pre>
控制臺輸出,
[3, 2, 1]
2.2 partial
functools.partial(func, *args, **keywords),函數裝飾器,返回一個新的partial對象。調用partial對象和調用被修飾的函數func相同,只不過調用partial對象時傳入的參數個數通常要少于調用func時傳入的參數個數。當一個函數func可以接收很多參數,而某一次使用只需要更改其中的一部分參數,其他的參數都保持不變時,partial對象就可以將這些不變的對象凍結起來,這樣調用partial對象時傳入未凍結的參數,partial對象調用func時連同已經被凍結的參數一同傳給func函數,從而可以簡化調用過程。
如果調用partial對象時提供了更多的參數,那么他們會被添加到args的后面,如果提供了更多的關鍵字參數,那么它們將擴展或者覆蓋已經凍結的關鍵字參數。
partial對象的調用如下,
import functools
def add(a,b):
return a + b
add3 = functools.partial(add,3)
add5 = functools.partial(add,5)
print add3(4)
print add5(10)</code></pre>
控制臺輸出,
2.3 reduce
與Python內置的reduce函數一樣,為了向Python3過渡;
import functools
a = range(1,6)
print functools.reduce(lambda x,y:x+y,a)</code></pre>
控制臺輸出,
2.4 total_ordering
這是一個類裝飾器,給定一個類,這個類定義了一個或者多個比較排序方法,這個類裝飾器將會補充其余的比較方法,減少了自己定義所有比較方法時的工作量;
被修飾的類必須至少定義 __lt__(), __le__(),__gt__(),__ge__()中的一個,同時,被修飾的類還應該提供 __eq__()方法。
from functools import total_ordering
class Person:
# 定義相等的比較函數
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()))
p1 = Person()
p2 = Person()
p1.lastname = "123"
p1.firstname = "000"
p2.lastname = "1231"
p2.firstname = "000"
print p1 < p2
print p1 <= p2
print p1 == p2
print p1 > p2
print p1 >= p2</code></pre>
控制臺輸出,
True
True
False
False
False
2.5 update_wrapper
更新一個包裹(wrapper)函數,使其看起來更像被包裹(wrapped)的函數。
可選的參數指定了被包裹函數的哪些屬性直接賦值給包裹函數的對應屬性,同時包裹函數的哪些屬性要更新而不是直接接受被包裹函數的對應屬性,參數assigned的默認值對應于模塊級常量WRAPPER_ASSIGNMENTS(默認地將被包裹函數的 __name__, __module__,和 __doc__ 屬性賦值給包裹函數),參數updated的默認值對應于模塊級常量WRAPPER_UPDATES(默認更新wrapper函數的 __dict__ 屬性)。
這個函數的主要用途是在一個裝飾器中,原函數會被裝飾(包裹),裝飾器函數會返回一個wrapper函數,如果裝飾器返回的這個wrapper函數沒有被更新,那么它的一些元數據更多的是反映wrapper函數定義的特征,無法反映wrapped函數的特性。
2.6 wraps
這個函數可用作一個裝飾器,簡化調用update_wrapper的過程,調用這個函數等價于調用partial(update_wrapper, wrapped = wrapped, assigned = assigned,updated = updated)。
from functools import wraps
def my_decorator(f):
@wraps(f)
def wrapper(args,**kwds):
print "Calling decorated function"
return f(args,**kwds)
return wrapper
@my_decorator
def example():
"""DocString"""
print "Called example function"
example()
print example.name
print example.doc</code></pre>
控制臺輸出,
Calling decorated function
Called example function
example
DocString
可以看到,最終調用函數example時,是經過 @my_decorator裝飾的,裝飾器的作用是接受一個被包裹的函數作為參數,對其進行加工,返回一個包裹函數,代碼使用 @functools.wraps裝飾將要返回的包裹函數wrapper,使得它的 __name__, __module__,和 __doc__ 屬性與被裝飾函數example完全相同,這樣雖然最終調用的是經過裝飾的example函數,但是某些屬性還是得到維護。
如果在 @my_decorator的定義中不使用 @function.wraps裝飾包裹函數,那么最終example.__name__ 將會變成'wrapper',而example.__doc__ 也會丟失。
將 @wraps(f)注釋掉,然后運行程序,控制臺輸出,
Calling decorated function
Called example function
wrapper
None
3 Reference
來自:http://www.cnblogs.com/zhbzz2007/p/6001827.html