python中的functools模塊


functools模塊可以作用於所有的可以被調用的對象,包括函數 定義了__call__方法的類等

  1 functools.cmp_to_key(func)

    將比較函數(接受兩個參數,通過比較兩個參數的大小返回負值,0,或者正數)轉換為key function(返回一個值用來比較或者排序的可調用對象),

    例如: sorted(iterable, functools.cmp_to_key(locale.strcoll))

def cmp1(n1, n2):
    return n1 - n2


a = [1, 6, 2, 9]
print(sorted(a, key=functools.cmp_to_key(cmp1)))

  2 @functools.lru_cache(maxsize=128, typed=False)

    首先這是一個裝飾器

    其次,介紹一下LRU算法:

      LRU是最常用的緩存算法,全稱叫“Least Recently Used”,顧名思義,就是在緩存miss 並且緩存空間已滿的時候,將最久沒訪問過的數據刪除從而騰出空間。

    然后,說一下這個裝飾器的兩個參數的含義:

      maxsize: 表示緩存大小,如果設置為None,表示不限制,設置為0表示不啟用緩存機制

      typed:如果設置為True,則該裝飾器所裝飾的函數的參數即使值相等(比如說 3 == 3.0 ),但類型不同(一個是整型一個是浮點),也會被區分對待為不同的緩存

    然后,說明一下這個裝飾器對所裝飾的函數的要求,

      1 函數的參數接收的值必須是不可變對象,像字符串,數字,元組等都屬於此列 

      2 其次函數返回的對象最好也是不可變對象,當然這一點沒有硬性要求,但是道理大家懂。

    來一個栗子:

@functools.lru_cache(2526)
def get_resource(page):

    url = "https://urls_does_not_contain_pornographic_informations/%s" % page

    try:
        with urllib.request.urlopen(url) as s:
            return s.read()
    except urllib.error.HTTPError:
        return 'Not Found'


for i in range(1, 2526):
    pep = get_resource(i)
    print(pep)

  3 @functools.total_ordering

    首先這是一個類裝飾器,這個類裝飾器要求它所定義的類中必須定義:

      1  小於__lt__(), 小於等於__le__(),大於__gt__(),大於等於__ge__()中的一個

      2  還要定義等於__eq__()方法。

    只要我們按照要求定義了這些方法,該裝飾器就會為我們完成其余的比較排序方法 。

  4 functools.partial(func, *args, **keywords)

     類似於這樣:

def abc(a, b):
    print a + b


def partial(func, *args, **kwargs):
    args_li = list(args)

    def inner(*nargs, **nkwargs):
        args_li.extend(nargs)
        kwargs.update(nkwargs)
        return func(*args_li, **kwargs)

    return inner


new_abc = partial(abc, 2)

new_abc(4)

實際上就是給某個函數加上幾個固定參數然后返回一個新的函數,對於多個對象更新相同的值來說可以用到。比如:

from functools import partial


class Test(object):
    def __init__(self):
        self.name = "lala"
        self.age = 20


def _update_attr(obj, update_dic):
    map(lambda item: setattr(obj, item[0], item[1]), update_dic.iteritems())


update_attr = partial(_update_attr, update_dic={"name": "mncu", "age": 18})

test_obj_list = [Test() for i in xrange(20)]

map(update_attr, test_obj_list)

for test_obj in test_obj_list:
    print test_obj.name, test_obj.age

   5 class functools.partialmethod(func, *args, **keywords)

    作用類似於上面的partial函數,但這個方法作用於類的方法,返回的是方法而不是函數

>>> class Cell(object):
...     def __init__(self):
...         self._alive = False
...     @property
...     def alive(self):
...         return self._alive
...     def set_state(self, state):
...         self._alive = bool(state)
...     set_alive = partialmethod(set_state, True)
...     set_dead = partialmethod(set_state, False)
...
>>> c = Cell()
>>> c.alive
False
>>> c.set_alive()
>>> c.alive
True

   6 functool.update_wrapper(wrapper, wrapped[, assigned][, updated])

      functools.wraps(wrapped[, assigned][, updated])

    在python中,當一個函數被裝飾器裝飾后,這個函數名字對應的函數對象實際上是那個裝飾器函數,也就是該函數名對應的的__name__以及__doc__實際上已經改變了,這就導致很難調試。而update_wrapper以及wraps就是用來解決這個問題。

#!/usr/bin/env python
# encoding: utf-8

def wrap(func):
    def call_it(*args, **kwargs):
        """wrap func: call_it"""
        print 'before call'
        return func(*args, **kwargs)
    return call_it

@wrap
def hello():
    """say hello"""
    print 'hello world'

from functools import update_wrapper
def wrap2(func):
    def call_it(*args, **kwargs):
        """wrap func: call_it2"""
        print 'before call'
        return func(*args, **kwargs)
    return update_wrapper(call_it, func)

@wrap2
def hello2():
    """test hello"""
    print 'hello world2'

if __name__ == '__main__':
    hello()
    print hello.__name__
    print hello.__doc__

    print
    hello2()
    print hello2.__name__
    print hello2.__doc__

結果:

  before call
  hello world
  call_it
  wrap func: call_it

  before call
  hello world2
  hello2
  test hello

from functools import wraps
def wrap3(func):
    @wraps(func)
    def call_it(*args, **kwargs):
        """wrap func: call_it2"""
        print 'before call'
        return func(*args, **kwargs)
    return call_it

@wrap3
def hello3():
    """test hello 3"""
    print 'hello world3'

結果:

  before call
  hello world3
  hello3
  test hello 3

 

參考:

  https://blog.theerrorlog.com/simple-lru-cache-in-python-3.html, 作者: Kay Zheng  

  http://www.wklken.me/posts/2013/08/18/python-extra-functools.html  作者:WKLKEN 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM