python 3クローズドパッケージとアクセサリー

19660 ワード

クローズドパックとアクセサリー
  • 閉パッケージ
  • デコレーション
  • 標準ライブラリのデコレーション
  • functools.lru_cache
  • 単分派汎関数
  • クローズドパッケージ
  • 閉パケット値は、関数定義体における参照を含む役割ドメインを拡張する関数であるが、定義体に定義されていない非グローバル変数
  • である.


  • 例1
    def make_avg():
        series = []     #           ---
        def ave(n):                     #|
            series.append(n)            #       
            total = sum(series)         #|
            return total/len(sries)     ---
        return ave
    #     :
    a = make_avg()
    a(10)
    a(11)
    

    上記の方法は効率的ではありません.すべての値を履歴に保存するには、現在の値と長さを格納するのがより良いです.
    例2
    def make_ave():
        count=0
        res = 0
        
        def aver(n):
            count += 1
            res += n
            return res / count
        return aver
    

    例2 spyderプロンプトエラーではコンパイルできません.countが数値または可変のタイプである場合、count+=1文の役割はcount=count+1と同様にaverでcountに一度付与されると、countが局所変数になるので、countは自由変数ではなく、閉パケットに保存されません.例1で問題ないのはappendを呼び出しsumとlenに伝えるためである.
  • 解決方法:nonlocal
  • を追加
    def make_ave():
        count=0
        res = 0
        
        def aver(n):
            nonlocal count, res
            count += 1
            res += n
            return res / count
        return aver
    

    デコレーション
    简単な装饰器を実现する时、私达はこの関数が不十分だと感じて、私はこの関数の基础の上でいくつかの余分な共通の机能を広げたいと思って、しかしこの関数はまたとても重要なため、直接コードに侵入して変えることができなくて、加えてその他の関数もこのような机能が必要かもしれなくて、このような@xxxのものです
    #             
    def deco(fun):
        def wap(*args, **kargs):
            time_start = time.time()
            fun(*args, **kargs)
            time_end = time.time()
            print('running time :', time_end-time_start)
        return wap
    
    @deco
    def Afun1(a, b,c):
        time.sleep(1)
        print('a+b+c=',a+b+c)
    Afun1(1,3,4) 
    
    #7.7
    '''
            
    '''
    import time 
    def clock(f):
        def clocked(*args):
            t0 = time.perf_counter()
            result = f(*args)
            ela = time.perf_counter() - t0
            name = f.__name__
            arg_str = ', '.join(repr(arg) for arg in args)
            print('[%0.8fs] %s(%s) ->%r' % (ela, name, arg_str, result))
            return result
        return clocked
    
    @clock
    def snooze(sec):
        time.sleep(sec)
    
    @clock
    def fact(n):
        return 1 if n < 2 else n*fact(n-1)
    
    if __name__=='__main__':
        print('*'*40, 'calling snooze(.123)')
        snooze(.123)
        print('*'*40, 'calling snooze(6)')
        fact(6)
    

    次のようになります.
    def snooze(sec):
        time.sleep(sec)
    clock(sbooze)
    

    factはclocked関数の参照を保存し、fact(n)を呼び出すたびにclocked(n)が実行され、clockedは大体次のことをしました.
  • 記録初期時間t 0
  • 元のfact関数を呼び出し、結果
  • を保存する
  • 計算経過時間
  • 収集データのフォーマット
  • は、ステップ2の結果
  • を返す.


  • スタンダードライブラリの装飾器
  • functools.lru_cache
  • singledispatch


  • functools.lru_cache
  • はメモ機能を実現し、時間のかかる関数結果を
  • に保存する.
    例3
    @clock
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-2) + fibonacci(n-1)
    
    print(fibonacci(6))
    #        ,       
    

    改良:
    import functools
    
    @functools.lru_cache()
    @clock
    def fibonacci(n):
        if n < 2:
            return n
        return fibonacci(n-2) + fibonacci(n-1)
        
    print result:
    [0.00000030s] fibonacci(0) ->0
    [0.00000030s] fibonacci(1) ->1
    [0.00002180s] fibonacci(2) ->1
    [0.00000060s] fibonacci(3) ->2
    [0.00004260s] fibonacci(4) ->3
    [0.00000040s] fibonacci(5) ->5
    [0.00006430s] fibonacci(6) ->8
    8
    
  • 注意:lru_Cacheは、2つのオプションのパラメータを使用して構成できます.
  • lru_cache(maxsize=128, typed = False)
    

    maxsizeは、2のサブべき乗の呼び出し結果を格納する回数を指定します.typedパラメータがTrueに設定されている場合は、異なるパラメータを別々に保存します.ディクショナリは結果を格納するので、パラメータはハッシュ可能でなければなりません.
    例1実現のclock装飾器の欠点:キーワードをサポートせず、唄装飾を隠した_name__および_doc__プロパティ、functoolsを使用します.wraps()は解決できます.
    def clock(func):
        @functools.wraps(func)
        def clock(*args, **kargs):
        
    

    シングルディスパッチ汎関数
    pythonはリロードメソッド関数をサポートしていないのでsingledispatch装飾器を使用して全体シナリオを複数のモジュールに分割します.
    from functools import singledispatch
    from collections import abc
    import numbers
    import html
    
    @singledispatch   #    object      
    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)