python 中的functools-高階函數和操作集工具。

functools 模塊是高階函數集,高階函數集作用於其它函數或返回其它函數,一般來說,任何可調用的對象都可以被當作這個模塊的一個目標函數。

  1. @functools.lru_cache(maxsize=128, typed=False)
  • 裝飾一個函數,使函數的調用可以被保存,保存最近 maxsize次的調用。當一個耗時的或O/I函數使用相周的參數時,被週期性的調用,對最近調用的結果的緩存,能提高執行效率,減小運時間。
  • 由於是用字典緩存調用的結果,所以,函數的位置參數和關鍵字參數要是能被哈希的。
  • 不同的參數類型 被認爲是不同的一次調用,會分別別緩存。比如,f(a=1,b=2) 和 f(b=2,a=1) 鍵字參數的位置順序不同,兩次調用會產生兩次緩存。
  • 如果maxsize設置爲None,那麼LRU(最近使用的)特性會被禁止,緩存將無限制地增長。LRU 特性在maxise是2的倍數時性能最好。
  • 被.lru_cache裝飾的函數會增加一個cache_into()函數方法,這個函數返回帶關鍵字命名參數的元組,分別爲hits, misses, maxsize和currsize, 有助於測試緩存帶來的效率提升和計算參數的最大量。
  • ecorator還提供了一個cache_clear()函數,用於清除或禁用緩存
  • 一個對最近使用的進行記錄的緩存,如果緩存大多數的調用能最大限度的的用於推斷後續的調用(比如說,在新新網站上一篇非常火的文章,每天都會更新),那麼它會帶來最大的工作效率。緩存的大小限制確保了緩存不會因爲長時間運行的進和而無休止的增長,比如說web服務。
  • 一般來說,LRU cache特性應該用在你想要利用之前的計值的地方。綜上所述,如果函數的執行會產生副作用,函數在每次調用時都會創建新的可變對象,或者不是純函數比如像time() or random()這樣的函,那麼使用LRU cache就沒有什麼義意了。

LRU cache 用在靜態web內容:

@lru_cache(maxsize=32)
def get_pep(num):
    'Retrieve text of a Python Enhancement Proposal'
    resource = 'http://www.python.org/dev/peps/pep-%04d/' % num
    try:
        with urllib.request.urlopen(resource) as s:
            return s.read()
    except urllib.error.HTTPError:
        return 'Not Found'

這多次調用get_pep函數,下次的調用不需要用到之前的調用,每次調用都會得到新的對象。LRU cache用在此處沒有什麼意義.

>>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
...     pep = get_pep(n)
...     print(n, len(pep))

>>> get_pep.cache_info()
CacheInfo(hits=3, misses=8, maxsize=32, currsize=8)

利用緩存實現動態編程技術,高效計算Fibonacci numbers:

from functools import lru_cache
import time
@lru_cache(maxsize=32)
def fib(n):
    if n < 2:
        return n
    return fib(n-1) + fib(n-2)

now = time.time()

>>>[fib(n) for n in range(10000)]
[0, 1, 1, 2, 3,... ]
>>> end =time.time() - now
>>> print("end:", end)
end: 4.142906904220581 # 計算位數10000,如沒有@lru_cache(maxsize=32)直接卡住
>>> print(fib.cache_info())
CacheInfo(hits=19996, misses=10000, maxsize=32, currsize=32)
  1. class functools.partialmethod(func, *args, **keywords)
  • 返回一個新的局部方法的描述符,這個描述符的行爲和原方法很像,也是作爲一個方法存在,而不是可直接調用的函數。
  • func 必須是一個描述符或是可調用的(這兩個像函數一樣的,用描述符來表的一個可操作的對象)
  • 當func是一個描述符時(比如一個正常的python函數,classmethod, staticmethod(),abstractmenthod() 或者 別的局部方法的實例),那麼會調用__ get __ 取得底層描述符,並且返回一個合適的局部對象作爲結果。
    注:我們可以簡單理解爲爲方法不同參數的調用過程,封裝成一個了個新方法,隱匿了傳參過程,這個新方法將執行相應參數在原函數相同的過程。
>>> 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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章