1. 程式人生 > >python的functools模組常用方法介紹

python的functools模組常用方法介紹

functools模組中有兩個方法是從_functools引入的,分別是partial和reduce函式。
functools模組是python2.5版本新增的模組。

1.偏函式partial
python中的偏函式與數學的偏函式意義不同,python中的partial函式用於當某個函式的引數值為固定時使用。引數可以為位置引數args,也可以為keyword引數kargs
(1) 不帶預設引數的加法函式
例如,當我們要求三個數的加法時,我們可以定義一個函式如下:

from functools import partial
def add(a, b, c):
    return a + b + c
print
add(1, 2, 3)

輸出:

6

(2) 帶預設引數的加法函式
如果引數a為固定值100,則我們可以利用partial函式改寫如下:

def add(a, b, c):
    return a + b + c
print "add", add(1, 2, 3)
add_plus = partial(add, 100)
print "partial(add, 100)", add_plus(5, 6)
add_plus = partial(add, 100, 200)
print "partial(add, 100, 200)", add_plus(5)

輸出結果為:

add 6
partial(add
, 100) 111 partial(add, 100, 200) 305

當函式中某些引數有預設值時,partial函式也能為預設引數匹配正確的位置。
定義一個含有預設引數的函式:

def add(a, b=333, c):
    return a + b + c
print "add", add(1, 2)

輸出結果:

  File "E:\python_program\leetcode\python_knowledge\functools_test.py", line 10
    def add(a, b=333, c):
SyntaxError: non-default argument follows default argument

丟擲SyntaxError異常,原來python函式的設定有預設值的引數必須放在函式引數的最後。
重新定義:

def add(a, b=333, c=6):
    print "a,b,c的值分別為:",a,b,c
    return a + b + c
print "add", add(1, 2)
add_plus = partial(add, 100)
print "partial(add, 100)", add_plus(5, 7)
add_plus = partial(add, 100, 200)
print "partial(add, 100, 200)", add_plus(5)

輸出結果:

add 
a,b,c的值分別為: 1 2 6
9
partial(add, 100) 
a,b,c的值分別為: 100 5 7
112
partial(add, 100, 200) 
a,b,c的值分別為: 100 200 5
305

從返回結果可以看出,
當定義偏函式為partial(add, 100)時,其將100按add方法的順序賦值給了引數a,因此呼叫add_plus(5, 7)時,5賦值給了b,7賦值給了c,因此相加的結果為112。
當定義偏函式為partial(add, 100, 200)時,其將100給了預設引數a,200給了預設函式b,因此呼叫add_plus(5)時,5賦值給了c,因此相加的結果為305。
注意:呼叫add_plus方法的引數個數=add方法的引數個數-partial的預設引數個數。
(3) 帶位置引數和keyword引數的函式

def add(*args, **kargs):
    print "args的值為:",args
    print "kargs的值為:",kargs

print "add", add(1, 2)
new_add = partial(add,1,2,3,a=100,b=200,c=300)
print "new_add", new_add(4,5,e=400,f=500)

輸出結果:

add args的值為: (1, 2)
kargs的值為: {}
None
new_add args的值為: (1, 2, 3, 4, 5)
kargs的值為: {'a': 100, 'c': 300, 'b': 200, 'e': 400, 'f': 500}
None

從結果可以看出,函式可以傳遞任何形式的引數,位置引數會追加到args中,keyword引數會追加到kargs。

2.reduce
collections中的reduce函式與python內建的reduce()函式功能相同,在該模組中設定該函式的目的是為了與python3相容。

3.update_wrapper

4.wraps
functools.wraps(wrapped[, assigned][, updated])
This is a convenience function for invoking partial(update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated) as a function decorator when defining a wrapper function.

例如(python2.7.2官方文件中的例子):

>>> 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()
Calling decorated function
Called example function
>>> example.__name__
'example'
>>> example.__doc__
'Docstring'

結果說明:
example函式被裝飾器my_decorator修飾,裝飾器的內部函式被wraps函式修飾,需要注意的是,被wraps修飾後,example函式的名字和說明文件與example函式一致,但是去掉@wraps(f)修飾後,輸出的example函式名稱為wrapper,說明文件為None。

5.total_ordering(2.7版本新增功能)
total_ordering是實現更多比較排序方法類的裝飾器。簡化了比較操作。該類必須定義一下方法中的一種 lt(), le(), gt(), or ge(),另外必須定義 eq() 方法。
例子:

class Student:
    def __init__(self, firstname, lastname):
        self.firstname = firstname
        self.lastname = lastname

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

a = Student("ab", "cd")
b = Student("ac", "cd")

print "a<b", a<b
print "a", a
print "b", b
print "sorted([a,b])", sorted([a,b])

輸出:

a<b True
a <__main__.Student instance at 0x0000000002A46288>
b <__main__.Student instance at 0x0000000002A462C8>
sorted([a,b]) [<__main__.Student instance at 0x0000000002A46288>, <__main__.Student instance at 0x0000000002A462C8>]

注意:python的list、dict、int、string 都是可以比較大小的。

6.cmp_to_key(2.7版本新增功能)
functools.cmp_to_key(func)
該功能主要是為了解決python版本,函式不相容的問題,比如sorted(), min(), max(), heapq.nlargest(), heapq.nsmallest(), itertools.groupby()等函式。

拿sorted()函式舉例
在python2.x版本中,sorted函式的格式為sorted(iterable[, cmp[, key[, reverse]]])
,在python3.x版本中,sorted函式的格式為sorted(iterable[, key][, reverse]) 。所以當我們需要將python2.x的程式移植到python3.x的環境中時,我們需要把原來cmp引數位置的函式,轉變為可以傳遞給引數key函式,此時我們就需要用到collections模組下的cmp_to_key方法。
cmp_to_key函式的原始碼如下:

def cmp_to_key(mycmp):
    """Convert a cmp= function into a key= function"""
    class K(object):
        __slots__ = ['obj']
        def __init__(self, obj, *args):
            self.obj = obj
        def __lt__(self, other):
            return mycmp(self.obj, other.obj) < 0
        def __gt__(self, other):
            return mycmp(self.obj, other.obj) > 0
        def __eq__(self, other):
            return mycmp(self.obj, other.obj) == 0
        def __le__(self, other):
            return mycmp(self.obj, other.obj) <= 0
        def __ge__(self, other):
            return mycmp(self.obj, other.obj) >= 0
        def __ne__(self, other):
            return mycmp(self.obj, other.obj) != 0
        def __hash__(self):
            raise TypeError('hash not implemented')
    return K

比較函式是任何的可以接受兩個引數,並且在函式中比較他們的函式。如果第一個引數小於第二個引數,則返回一個負數;如果相等,則返回0;如果大於返回正數。
key函式接受一個引數,並按照返回的值排列順序。
sorted(iterable[, cmp[, key[, reverse]]]) 中的cmp引數形如cmp=lambda x,y: cmp(x.lower(), y.lower()).
cmp_to_key()函式使用例項:

from functools import cmp_to_key
s = [{"key":3},{"key":1},{"key":5}]
key = cmp_to_key(lambda x,y: x["key"] - y["key"])
b = sorted(s,key=key,reverse=True)
print b

輸出結果:

[{'key': 5}, {'key': 3}, {'key': 1}]