標準ライブラリのアクセサリーlru_Cacheと新しいsingledispatch
9565 ワード
Pythonには、property、classmethod、staticmethodの3つの装飾方法の関数が内蔵されています.
もう一つの一般的な装飾器はfunctoolsです.wrapsは、動作の良い装飾器の構築に協力する役割を果たしています.スタンダードライブラリで最も注目すべき2つのアクセサリーはlru_Cacheと新しいsingledispatch(Python 3.4が追加).この2つの装飾器はfunctoolsモジュールで定義されています.次に、それらをそれぞれ議論します.
1、functoolsを使用する.lru_cacheメモをとる
functools.lru_Cacheは非常に実用的な装飾器で、メモ機能を実現しています.これは最適化技術であり、同じパラメータが入力されたときに計算を繰り返すことを避けるために、時間のかかる関数の結果を保存します.LRUの3文字は「Least Recenly Used」の略で、キャッシュが無制限に増加しないことを示しており、しばらく使用しないキャッシュエントリは破棄されます.
n番目のフィボナッチ数を生成するこの遅い再帰関数はlru_を使用するのに適している.cache
結果:
時間の無駄なところは明らかです:fibonacci(1)は8回呼び出し、fibonacci(2)は5回呼び出しました・・・しかし、2行のコードを増やせばlru_Cache、性能が著しく改善
結果:
これにより、実行時間が半減し、nの値ごとに関数が1回しか呼び出されない.
特に注意して、lru_Cacheは、2つのオプションのパラメータを使用して構成できます.署名はfunctoolsですlru_Cache(maxsize=128、typed=False)maxsizeパラメータは、呼び出しの結果を格納する回数を指定します.キャッシュがいっぱいになると、古い結果は捨てられ、スペースが空けられます.最適なパフォーマンスを得るためには、maxsizeを2のべき乗に設定する必要があります.typedパラメータをTrueとすると,異なるパラメータタイプで得られた結果を別々に保存する,すなわち,通常等しいと考えられる浮動小数点数と整数パラメータ(例えば1と1.0)を区別する.ちなみにlru_Cacheは辞書を使用して結果を格納し、呼び出し時に入力された位置決めパラメータとキーワードパラメータに基づいてキーが作成されるためlru_Cache装飾の関数で、そのすべてのパラメータはハッシュ可能でなければなりません.
単発汎関数functools.singledispatch
Webアプリケーションをデバッグするツールを開発していると仮定し、HTMLを生成し、異なるタイプのPythonオブジェクトを表示したいと考えています.
もう一つの一般的な装飾器はfunctoolsです.wrapsは、動作の良い装飾器の構築に協力する役割を果たしています.スタンダードライブラリで最も注目すべき2つのアクセサリーはlru_Cacheと新しいsingledispatch(Python 3.4が追加).この2つの装飾器はfunctoolsモジュールで定義されています.次に、それらをそれぞれ議論します.
1、functoolsを使用する.lru_cacheメモをとる
functools.lru_Cacheは非常に実用的な装飾器で、メモ機能を実現しています.これは最適化技術であり、同じパラメータが入力されたときに計算を繰り返すことを避けるために、時間のかかる関数の結果を保存します.LRUの3文字は「Least Recenly Used」の略で、キャッシュが無制限に増加しないことを示しており、しばらく使用しないキャッシュエントリは破棄されます.
#
import time
import functools
def clock(func):
@functools.wraps(func)
def clocked(*args, **kwargs):
t0 = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - t0
name = func.__name__
arg_lst = []
if args:
arg_lst.append(', '.join(repr(arg) for arg in args))
if kwargs:
pairs = ['%s=%r' % (k, w) for k, w in sorted(kwargs.items())]
arg_lst.append(', '.join(pairs))
arg_str = ', '.join(arg_lst)
print('[%0.8fs] %s(%s) -> %r ' % (elapsed, name, arg_str, result))
return result
return clocked
n番目のフィボナッチ数を生成するこの遅い再帰関数はlru_を使用するのに適している.cache
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
if __name__=='__main__':
print(fibonacci(6))
結果:
[0.00000095s] fibonacci(0) -> 0
[0.00000095s] fibonacci(1) -> 1
[0.00007892s] fibonacci(2) -> 1
[0.00000095s] fibonacci(1) -> 1
[0.00000095s] fibonacci(0) -> 0
[0.00000095s] fibonacci(1) -> 1
[0.00003815s] fibonacci(2) -> 1
[0.00007391s] fibonacci(3) -> 2
[0.00018883s] fibonacci(4) -> 3
[0.00000000s] fibonacci(1) -> 1
[0.00000095s] fibonacci(0) -> 0
[0.00000119s] fibonacci(1) -> 1
[0.00004911s] fibonacci(2) -> 1
[0.00009704s] fibonacci(3) -> 2
[0.00000000s] fibonacci(0) -> 0
[0.00000000s] fibonacci(1) -> 1
[0.00002694s] fibonacci(2) -> 1
[0.00000095s] fibonacci(1) -> 1
[0.00000095s] fibonacci(0) -> 0
[0.00000095s] fibonacci(1) -> 1
[0.00005102s] fibonacci(2) -> 1
[0.00008917s] fibonacci(3) -> 2
[0.00015593s] fibonacci(4) -> 3
[0.00029993s] fibonacci(5) -> 5
[0.00052810s] fibonacci(6) -> 8
8
時間の無駄なところは明らかです:fibonacci(1)は8回呼び出し、fibonacci(2)は5回呼び出しました・・・しかし、2行のコードを増やせばlru_Cache、性能が著しく改善
@functools.lru_cache()
@clock
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)
if __name__=='__main__':
print(fibonacci(6))
結果:
[0.00000119s] fibonacci(0) -> 0
[0.00000119s] fibonacci(1) -> 1
[0.00010800s] fibonacci(2) -> 1
[0.00000787s] fibonacci(3) -> 2
[0.00016093s] fibonacci(4) -> 3
[0.00001216s] fibonacci(5) -> 5
[0.00025296s] fibonacci(6) -> 8
8
これにより、実行時間が半減し、nの値ごとに関数が1回しか呼び出されない.
特に注意して、lru_Cacheは、2つのオプションのパラメータを使用して構成できます.署名はfunctoolsですlru_Cache(maxsize=128、typed=False)maxsizeパラメータは、呼び出しの結果を格納する回数を指定します.キャッシュがいっぱいになると、古い結果は捨てられ、スペースが空けられます.最適なパフォーマンスを得るためには、maxsizeを2のべき乗に設定する必要があります.typedパラメータをTrueとすると,異なるパラメータタイプで得られた結果を別々に保存する,すなわち,通常等しいと考えられる浮動小数点数と整数パラメータ(例えば1と1.0)を区別する.ちなみにlru_Cacheは辞書を使用して結果を格納し、呼び出し時に入力された位置決めパラメータとキーワードパラメータに基づいてキーが作成されるためlru_Cache装飾の関数で、そのすべてのパラメータはハッシュ可能でなければなりません.
単発汎関数functools.singledispatch
Webアプリケーションをデバッグするツールを開発していると仮定し、HTMLを生成し、異なるタイプのPythonオブジェクトを表示したいと考えています.
import html
def htmlize(obj):
content = html.escape(repr(obj))
return '{}
'.format(content)
に、データ に じて のフォーマットを するように したいと います. str: の を';に き えます., 。
を しない int:10 と16 で を します. list:HTMLリストを し、 のタイプに じてフォーマットします. import html
from functools import singledispatch
from collections import abc
import numbers
@singledispatch
def htmlize(obj):
content = html.escape(repr(obj))
return '{}
'.format(content)@htmlize.register(str)def _(text): content = html.escape(text).replace('', '') return '{0}'.format(content)@htmlize.register(numbers.Integral)def _(n): return '{0} (0x{0:x})'.format(n)@htmlize.register(tuple)@htmlize.register(abc.MutableSequence)def _(seq): inner = ' '.join(htmlize(item) for item in seq) return ' ' + inner + ' '
: の は ではありません.いい で、 です. のregisterアクセサリーを ねて、 じ で なるタイプをサポートできます.print(htmlize({1, 2, 3}))
'{1, 2, 3}
'
print(htmlize(abs))
'
'
print(htmlize('Heimlich & Co.- a game'))
'Heimlich & Co.
- a game'
print(htmlize(42))
'42 (0x2a)'
print(htmlize(['alpha', 66, {3, 2, 1}]))
''' alpha 66 (0x42)
{1, 2, 3}
'''
singledispatchメカニズムの な は、システムの の と のモジュールに を できることです.その 、 しいモジュールに しいタイプが されると、そのタイプを するために しい を に できます.
:https://www.cnblogs.com/feifeifeisir/p/11576510.html