[python]戻り関数とアクセサリ

2957 ワード

戻り関数
関数を返します:関数は結果としてe.gを返します:
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

f = lazy_sum(1,2)   #   lazy_sum   ,    sum   f
f()  #   
#        lazy_sum(1,2)()
3

>呼び出しのたびに、同じパラメータが入力された場合でも、新しい関数が返されます.
f1 = lazy_sum(1, 3, 5, 7, 9)
f2 = lazy_sum(1, 3, 5, 7, 9)
f1==f2
>>>False

デコレータ
補足:関数オブジェクトにはnameプロパティe.gがあります.
def now():
    print('2015-3-25')
f = now
now.__name__
>>>'now'
f.__name__
>>>'now'

装飾の書き方:@funcName e.g:
def print_caller(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

def test():
    print('test')

@print_caller
test()

>>>call test():
>>>test

decoratorは実質的に関数を返すので、元のtest()関数は依然として存在しますが、同じ名前のtest変数が新しい関数を指しているだけで、test()を呼び出すとprint_で新しい関数が実行されます.caller()関数で返されるwrapper()関数.wrapper()関数のパラメータ定義は(*args,**kw)であるため、wrapper()関数は任意のパラメータの呼び出しを受け入れることができる.wrapper()関数では、まずログを印刷し、元の関数を呼び出します.だから、@print_callerは実行に相当します.
test = print_caller(test)

印刷関数の実行前後時間のexample:
def metric(func):
    def decorator(*args, **kw):
        print('start:%s' % int(time.time()))
        time.sleep(2)
        r = func(args, **kw)
        print('end:%s' % int(time.time()))
        return r
    return decorator

@metric
def test(a):
    print('test')

test()

>>>start:1554695731
>>>test
>>>end:1554695733


上記のいくつかの例は、decoratorがパラメータを伝達する必要がない場合であり、decoratorがパラメータを伝達する必要がある場合は、decoratorを返す高次関数e.gを記述する必要があります.
def add_text(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('text:%s' % text)
            r = func(args, **kw)
            return r
        return wrapper
    return decorator


@add_text('miao')
def test(a):
    print('test')

>>>text:miao
>>>test

実質的に3層のネスト、@add_textは実行に相当します.
test = add_text('miao')(test)

*decoratorの本質的なネスト戻り関数は、プロトタイプポインタが変化することを招き、nameなどの属性も変化し、上述のnameがtestからwrapperになるように、理論的にwrapperを追加すべきである.name = func.name、プロトタイプポインタを元の関数にポインタしますが、Pythonにはfunctoolsが内蔵されています.wrapsはこの処理をしました
import functools

#         
def print_caller(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

#        
def add_text(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('text:%s' % text)
            r = func(args, **kw)
            return r
        return wrapper
    return decorator